diff --git a/hnix.cabal b/hnix.cabal index 5ea512d..90a0cf9 100644 --- a/hnix.cabal +++ b/hnix.cabal @@ -2,7 +2,7 @@ -- -- see: https://github.com/sol/hpack -- --- hash: 7e613ce82a3337411d625301abd33a6d7f1c400edadbd602287027f2af1e4fdf +-- hash: 0e0438f43eaffbbd952e85bc24499b40e17f276ec7488f3a483e7d848ea1075d cabal-version: >= 1.10 name: hnix @@ -486,7 +486,6 @@ library ghc-options: -Wall build-depends: aeson - , ansi-wl-pprint , array >=0.4 && <0.6 , base >=4.9 && <5 , binary @@ -510,6 +509,7 @@ library , monadlist , mtl , optparse-applicative + , prettyprinter , process , regex-tdfa , regex-tdfa-text @@ -574,7 +574,6 @@ executable hnix ghc-options: -Wall build-depends: aeson - , ansi-wl-pprint , base >=4.9 && <5 , bytestring , containers @@ -588,6 +587,7 @@ executable hnix , mtl , optparse-applicative , pretty-show + , prettyprinter , repline , template-haskell , text @@ -633,7 +633,6 @@ test-suite hnix-tests build-depends: Diff , Glob - , ansi-wl-pprint , base >=4.9 && <5 , bytestring , containers @@ -651,6 +650,7 @@ test-suite hnix-tests , mtl , optparse-applicative , pretty-show + , prettyprinter , process , split , tasty @@ -696,8 +696,7 @@ benchmark hnix-benchmarks benchmarks ghc-options: -Wall build-depends: - ansi-wl-pprint - , base >=4.9 && <5 + base >=4.9 && <5 , bytestring , containers , criterion diff --git a/main/Main.hs b/main/Main.hs index db90625..8fcf34d 100644 --- a/main/Main.hs +++ b/main/Main.hs @@ -24,6 +24,8 @@ import qualified Data.Text as Text import qualified Data.Text.IO as Text import qualified Data.Text.Lazy.Encoding as TL import qualified Data.Text.Lazy.IO as TL +import Data.Text.Prettyprint.Doc +import Data.Text.Prettyprint.Doc.Render.Text import Nix import Nix.Convert import qualified Nix.Eval as Eval @@ -36,7 +38,6 @@ import Options.Applicative hiding (ParserResult(..)) import qualified Repl import System.FilePath import System.IO -import Text.PrettyPrint.ANSI.Leijen hiding ((<$>)) import qualified Text.Show.Pretty as PS main :: IO () @@ -127,8 +128,8 @@ main = do void $ liftIO $ Exc.evaluate $ Deep.force expr | otherwise = - liftIO $ displayIO stdout - . renderPretty 0.4 80 + liftIO $ renderIO stdout + . layoutPretty (LayoutOptions $ AvailablePerLine 80 0.4) . prettyNix . stripAnnotation $ expr where diff --git a/package.yaml b/package.yaml index 4d04cd1..c875ed8 100644 --- a/package.yaml +++ b/package.yaml @@ -55,7 +55,6 @@ ghc-options: dependencies: - base >= 4.9 && < 5 - - ansi-wl-pprint - bytestring - containers - data-fix @@ -98,7 +97,6 @@ library: source-dirs: src dependencies: - aeson - - ansi-wl-pprint - array >= 0.4 && < 0.6 - binary - deriving-compat >= 0.3 && < 0.6 @@ -112,6 +110,7 @@ library: - logict - megaparsec >= 6.5 && < 7.0 - monadlist + - prettyprinter - process - regex-tdfa - regex-tdfa-text @@ -158,6 +157,7 @@ executables: - hnix - aeson - pretty-show + - prettyprinter - repline - haskeline when: @@ -193,6 +193,7 @@ tests: - megaparsec - tasty-quickcheck - pretty-show + - prettyprinter when: - condition: "impl(ghcjs)" then: diff --git a/src/Nix/Exec.hs b/src/Nix/Exec.hs index 6779434..2793ea4 100644 --- a/src/Nix/Exec.hs +++ b/src/Nix/Exec.hs @@ -45,9 +45,10 @@ import Data.List import qualified Data.List.NonEmpty as NE import Data.List.Split import Data.Maybe (maybeToList) -import Data.Monoid +import Data.Semigroup import Data.Text (Text) import qualified Data.Text as Text +import Data.Text.Prettyprint.Doc import Data.Typeable import GHC.IO.Exception (IOErrorType(..)) import Network.HTTP.Client @@ -81,8 +82,6 @@ import qualified System.Info import System.IO.Error import System.Posix.Files import System.Process (readProcessWithExitCode) -import Text.PrettyPrint.ANSI.Leijen (text) -import qualified Text.PrettyPrint.ANSI.Leijen as P #ifdef MIN_VERSION_pretty_show import qualified Text.Show.Pretty as PS #endif @@ -558,8 +557,10 @@ instance (MonadFix m, MonadCatch m, MonadIO m, Alternative m, eres <- Lazy $ parseNixFileLoc path case eres of Failure err -> - throwError $ ErrorCall . show $ - text "Parse during import failed:" P. err + throwError $ ErrorCall . show $ fillSep $ + [ "Parse during import failed:" + , err + ] Success expr -> do Lazy $ ReaderT $ const $ modify (M.insert path expr) @@ -781,16 +782,16 @@ addTracing k v = do let rendered = if verbose opts >= Chatty #ifdef MIN_VERSION_pretty_show - then text $ PS.ppShow (void x) + then pretty $ PS.ppShow (void x) #else - then text $ show (void x) + then pretty $ show (void x) #endif else prettyNix (Fix (Fix (NSym "?") <$ x)) - msg x = text ("eval: " ++ replicate depth ' ') <> x - loc <- renderLocation span (msg rendered <> text " ...\n") + msg x = pretty ("eval: " ++ replicate depth ' ') <> x + loc <- renderLocation span (msg rendered <> " ...\n") liftIO $ putStr $ show loc res <- k v' - liftIO $ print $ msg rendered <> text " ...done" + liftIO $ print $ msg rendered <> " ...done" return res evalExprLoc :: forall e m. (MonadNix e m, Has e Options, MonadIO m) diff --git a/src/Nix/Options/Parser.hs b/src/Nix/Options/Parser.hs index 913163f..01adfa7 100644 --- a/src/Nix/Options/Parser.hs +++ b/src/Nix/Options/Parser.hs @@ -5,10 +5,10 @@ import Data.Char (isDigit) import Data.Maybe (fromMaybe) import Data.Text (Text) import qualified Data.Text as Text +import Data.Text.Prettyprint.Doc import Data.Time import Nix.Options import Options.Applicative hiding (ParserResult(..)) -import Text.PrettyPrint.ANSI.Leijen hiding ((<$>)) decodeVerbosity :: Int -> Verbosity decodeVerbosity 0 = ErrorsOnly diff --git a/src/Nix/Parser.hs b/src/Nix/Parser.hs index 57abb11..4f3ff24 100644 --- a/src/Nix/Parser.hs +++ b/src/Nix/Parser.hs @@ -62,6 +62,7 @@ import qualified Data.List.NonEmpty as NE import qualified Data.Map as Map import Data.Text (Text) import Data.Text hiding (map, foldr1, concat, concatMap, zipWith) +import Data.Text.Prettyprint.Doc (Doc, pretty) import qualified Data.Text.IO as T import Data.Typeable (Typeable) import Data.Void @@ -72,7 +73,6 @@ import Text.Megaparsec import Text.Megaparsec.Char import qualified Text.Megaparsec.Char.Lexer as L import Text.Megaparsec.Expr -import Text.PrettyPrint.ANSI.Leijen (Doc, text) infixl 3 <+> (<+>) :: MonadPlus m => m a -> m a -> m a @@ -437,17 +437,17 @@ reservedNames = HashSet.fromList type Parser = ParsecT Void Text Identity -data Result a = Success a | Failure Doc deriving (Show, Functor) +data Result a = Success a | Failure (Doc Void) deriving (Show, Functor) parseFromFileEx :: MonadIO m => Parser a -> FilePath -> m (Result a) parseFromFileEx p path = do txt <- liftIO (T.readFile path) - return $ either (Failure . text . parseErrorPretty' txt) Success + return $ either (Failure . pretty . parseErrorPretty' txt) Success $ parse p path txt parseFromText :: Parser a -> Text -> Result a parseFromText p txt = - either (Failure . text . parseErrorPretty' txt) Success $ + either (Failure . pretty . parseErrorPretty' txt) Success $ parse p "" txt {- Parser.Operators -} diff --git a/src/Nix/Pretty.hs b/src/Nix/Pretty.hs index 1d2dd20..e112036 100644 --- a/src/Nix/Pretty.hs +++ b/src/Nix/Pretty.hs @@ -24,6 +24,7 @@ import qualified Data.List.NonEmpty as NE import Data.Maybe (isJust, fromMaybe) import Data.Text (pack, unpack, replace, strip) import qualified Data.Text as Text +import Data.Text.Prettyprint.Doc import Nix.Atoms import Nix.Expr import Nix.Parser @@ -37,13 +38,12 @@ import Nix.Utils hiding ((<$>)) #endif import Nix.Value 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 +data NixDoc ann = NixDoc { -- | The rendered expression, without any parentheses. - withoutParens :: Doc + withoutParens :: Doc ann -- | The root operator is the operator at the root of -- the expression tree. For example, in '(a * b) + c', '+' would be the root @@ -54,16 +54,16 @@ data NixDoc = NixDoc -- we can add brackets appropiately } -mkNixDoc :: Doc -> OperatorInfo -> NixDoc +mkNixDoc :: Doc ann -> OperatorInfo -> NixDoc ann mkNixDoc d o = NixDoc { withoutParens = d, rootOp = o, wasPath = False } -- | A simple expression is never wrapped in parentheses. The expression -- behaves as if its root operator had a precedence higher than all -- other operators (including function application). -simpleExpr :: Doc -> NixDoc +simpleExpr :: Doc ann -> NixDoc ann simpleExpr d = mkNixDoc d (OperatorInfo minBound NAssocNone "simple expr") -pathExpr :: Doc -> NixDoc +pathExpr :: Doc ann -> NixDoc ann pathExpr d = (simpleExpr d) { wasPath = True } -- | An expression that behaves as if its root operator had a precedence lower @@ -71,7 +71,7 @@ pathExpr d = (simpleExpr d) { wasPath = True } -- 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). -leastPrecedence :: Doc -> NixDoc +leastPrecedence :: Doc ann -> NixDoc ann leastPrecedence = flip mkNixDoc $ OperatorInfo maxBound NAssocNone "least precedence" @@ -87,7 +87,7 @@ selectOp = getSpecialOperator NSelectOp hasAttrOp :: OperatorInfo hasAttrOp = getSpecialOperator NHasAttrOp -wrapParens :: OperatorInfo -> NixDoc -> Doc +wrapParens :: OperatorInfo -> NixDoc ann -> Doc ann wrapParens op sub | precedence (rootOp sub) < precedence op = withoutParens sub | precedence (rootOp sub) == precedence op @@ -97,104 +97,117 @@ wrapParens op sub -- Used in the selector case to print a path in a selector as -- "${./abc}" -wrapPath :: OperatorInfo -> NixDoc -> Doc +wrapPath :: OperatorInfo -> NixDoc ann -> Doc ann wrapPath op sub = - if wasPath sub then dquotes (text "$" <> braces (withoutParens sub)) - else wrapParens op sub + if wasPath sub + then dquotes $ "$" <> braces (withoutParens sub) + else wrapParens op sub -prettyString :: NString NixDoc -> Doc +prettyString :: NString (NixDoc ann)-> Doc ann prettyString (DoubleQuoted parts) = dquotes . hcat . map prettyPart $ parts - where prettyPart (Plain t) = text . concatMap escape . unpack $ t - prettyPart EscapedNewline = text "''\\n" - prettyPart (Antiquoted r) = text "$" <> braces (withoutParens r) + where prettyPart (Plain t) = pretty . concatMap escape . unpack $ t + prettyPart EscapedNewline = "''\\n" + prettyPart (Antiquoted r) = "$" <> braces (withoutParens r) escape '"' = "\\\"" escape x = maybe [x] (('\\':) . (:[])) $ toEscapeCode x prettyString (Indented _ parts) - = group $ nest 2 (squote <> squote <$$> content) <$$> squote <> squote + = group $ nest 2 $ vcat [dsquote, content, dsquote] where + dsquote = squote <> squote 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 - prettyPart EscapedNewline = text "\\n" - prettyPart (Antiquoted r) = text "$" <> braces (withoutParens r) + prettyPart (Plain t) = pretty . unpack . replace "${" "''${" . replace "''" "'''" $ t + prettyPart EscapedNewline = "\\n" + prettyPart (Antiquoted r) = "$" <> braces (withoutParens r) -prettyParams :: Params NixDoc -> Doc -prettyParams (Param n) = text $ unpack n +prettyParams :: Params (NixDoc ann) -> Doc ann +prettyParams (Param n) = pretty $ unpack n prettyParams (ParamSet s v mname) = prettyParamSet s v <> case mname of - Nothing -> empty - Just name | Text.null name -> empty - | otherwise -> text "@" <> text (unpack name) + Nothing -> mempty + Just name | Text.null name -> mempty + | otherwise -> "@" <> pretty (unpack name) -prettyParamSet :: ParamSet NixDoc -> Bool -> Doc +prettyParamSet :: ParamSet (NixDoc ann) -> Bool -> Doc ann prettyParamSet args var = encloseSep (lbrace <> space) (align (space <> rbrace)) sep (map prettySetArg args ++ prettyVariadic) where prettySetArg (n, maybeDef) = case maybeDef of - Nothing -> text (unpack n) - Just v -> text (unpack n) <+> text "?" <+> withoutParens v - prettyVariadic = [text "..." | var] + Nothing -> pretty (unpack n) + Just v -> pretty (unpack n) <+> "?" <+> withoutParens v + prettyVariadic = ["..." | var] sep = align (comma <> space) -prettyBind :: Binding NixDoc -> Doc +prettyBind :: Binding (NixDoc ann) -> Doc ann prettyBind (NamedVar n v _p) = prettySelector n <+> equals <+> withoutParens v <> semi prettyBind (Inherit s ns _p) - = text "inherit" <+> scope <> align (fillSep (map prettyKeyName ns)) <> semi - where scope = maybe empty ((<> space) . parens . withoutParens) s + = "inherit" <+> scope <> align (fillSep (map prettyKeyName ns)) <> semi + where scope = maybe mempty ((<> space) . parens . withoutParens) s -prettyKeyName :: NKeyName NixDoc -> Doc -prettyKeyName (StaticKey "") = dquotes $ text "" +prettyKeyName :: NKeyName (NixDoc ann) -> Doc ann +prettyKeyName (StaticKey "") = dquotes "" prettyKeyName (StaticKey key) - | HashSet.member key reservedNames = dquotes $ text $ unpack key -prettyKeyName (StaticKey key) = text . unpack $ key + | HashSet.member key reservedNames = dquotes $ pretty $ unpack key +prettyKeyName (StaticKey key) = pretty . unpack $ key prettyKeyName (DynamicKey key) = runAntiquoted (DoubleQuoted [Plain "\n"]) - prettyString ((text "$" <>) . braces . withoutParens) key + prettyString (("$" <>) . braces . withoutParens) key -prettySelector :: NAttrPath NixDoc -> Doc +prettySelector :: NAttrPath (NixDoc ann) -> Doc ann prettySelector = hcat . punctuate dot . map prettyKeyName . NE.toList -prettyAtom :: NAtom -> NixDoc -prettyAtom atom = simpleExpr $ text $ unpack $ atomText atom +prettyAtom :: NAtom -> NixDoc ann +prettyAtom atom = simpleExpr $ pretty $ unpack $ atomText atom -prettyNix :: NExpr -> Doc +prettyNix :: NExpr -> Doc ann prettyNix = withoutParens . cata exprFNixDoc -prettyOriginExpr :: NExprLocF (Maybe (NValue m)) -> Doc +prettyOriginExpr :: NExprLocF (Maybe (NValue m)) -> Doc ann prettyOriginExpr = withoutParens . go where go = exprFNixDoc . annotated . getCompose . fmap render - render Nothing = simpleExpr $ text "_" + render Nothing = simpleExpr $ "_" render (Just (NValue (reverse -> p:_) _)) = go (_originExpr p) - render (Just (NValue _ _)) = simpleExpr $ text "?" - -- simpleExpr $ foldr ((<$>) . parens . indent 2 . withoutParens + render (Just (NValue _ _)) = simpleExpr "?" + -- simpleExpr $ foldr ((\x y -> vsep [x, y]) . parens . indent 2 . withoutParens -- . go . originExpr) -- mempty (reverse ps) -exprFNixDoc :: NExprF NixDoc -> NixDoc +exprFNixDoc :: NExprF (NixDoc ann) -> NixDoc ann 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 + NList xs -> simpleExpr $ group $ nest 2 $ vsep $ concat $ + [ [lbracket] + , map (wrapParens appOpNonAssoc) xs + , [rbracket] + ] NSet [] -> simpleExpr $ lbrace <> rbrace - NSet xs -> simpleExpr $ group $ - nest 2 (vsep $ lbrace : map prettyBind xs) <$> rbrace + NSet xs -> simpleExpr $ group $ nest 2 $ vsep $ concat $ + [ [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) + NRecSet xs -> simpleExpr $ group $ nest 2 $ vsep $ concat $ + [ [recPrefix <> lbrace] + , map prettyBind xs + , [rbrace] + ] + NAbs args body -> leastPrecedence $ nest 2 $ vsep $ + [ prettyParams args <> colon + , withoutParens body + ] NBinary NApp fun arg -> mkNixDoc (wrapParens appOp fun <+> wrapParens appOpNonAssoc arg) appOp NBinary op r1 r2 -> flip mkNixDoc opInfo $ hsep [ wrapParens (f NAssocLeft) r1 - , text $ unpack $ operatorName opInfo + , pretty $ unpack $ operatorName opInfo , wrapParens (f NAssocRight) r2 ] where @@ -202,18 +215,18 @@ exprFNixDoc = \case f x | associativity opInfo /= x = opInfo { associativity = NAssocNone } | otherwise = opInfo NUnary op r1 -> - mkNixDoc (text (unpack (operatorName opInfo)) <> wrapParens opInfo r1) opInfo + mkNixDoc (pretty (unpack (operatorName opInfo)) <> wrapParens opInfo r1) opInfo where opInfo = getUnaryOperator op NSelect r' attr o -> (if isJust o then leastPrecedence else flip mkNixDoc selectOp) $ wrapPath selectOp r <> dot <> prettySelector attr <> ordoc where r = flip mkNixDoc selectOp $ wrapParens appOpNonAssoc r' - ordoc = maybe empty (((space <> text "or") <+>) . wrapParens appOpNonAssoc) o + ordoc = maybe mempty (((space <> "or") <+>) . wrapParens appOpNonAssoc) o NHasAttr r attr -> - mkNixDoc (wrapParens hasAttrOp r <+> text "?" <+> prettySelector attr) hasAttrOp - NEnvPath p -> simpleExpr $ text ("<" ++ p ++ ">") - NLiteralPath p -> pathExpr $ text $ case p of + mkNixDoc (wrapParens hasAttrOp r <+> "?" <+> prettySelector attr) hasAttrOp + NEnvPath p -> simpleExpr $ pretty ("<" ++ p ++ ">") + NLiteralPath p -> pathExpr $ pretty $ case p of "./" -> "./." "../" -> "../." ".." -> "../." @@ -222,20 +235,28 @@ exprFNixDoc = \case | "./" `isPrefixOf` txt -> txt | "../" `isPrefixOf` txt -> txt | otherwise -> "./" ++ txt - NSym name -> simpleExpr $ text (unpack name) - NLet binds body -> leastPrecedence $ group $ text "let" <$> indent 2 ( - vsep (map prettyBind binds)) <$> text "in" <+> withoutParens body + NSym name -> simpleExpr $ pretty (unpack name) + NLet binds body -> leastPrecedence $ group $ vsep $ + [ "let" + , indent 2 (vsep (map prettyBind binds)) + , "in" <+> withoutParens body + ] 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) + group $ nest 2 $ vsep $ + [ "if" <+> withoutParens cond + , align ("then" <+> withoutParens trueBody) + , align ("else" <+> withoutParens falseBody) + ] + NWith scope body -> leastPrecedence $ vsep $ + [ "with" <+> withoutParens scope <> semi + , align $ withoutParens body + ] + NAssert cond body -> leastPrecedence $ vsep $ + [ "assert" <+> withoutParens cond <> semi + , align $ withoutParens body + ] where - recPrefix = text "rec" <> space + recPrefix = "rec" <> space fixate :: Functor f => (a -> f (Fix f)) -> Free f a -> Fix f fixate g = Fix . go @@ -243,7 +264,7 @@ fixate g = Fix . go go (Pure a) = g a go (Free f) = fmap (Fix . go) f -prettyNValueNF :: Functor m => NValueNF m -> Doc +prettyNValueNF :: Functor m => NValueNF m -> Doc ann prettyNValueNF = prettyNix . valueToExpr where check :: NValueNF m -> Fix (NValueF m) @@ -288,27 +309,33 @@ removeEffects = Free . fmap dethunk removeEffectsM :: MonadVar m => NValueF m (NThunk m) -> m (NValueNF m) removeEffectsM = fmap Free . traverse dethunk -prettyNValueF :: MonadVar m => NValueF m (NThunk m) -> m Doc +prettyNValueF :: MonadVar m => NValueF m (NThunk m) -> m (Doc ann) prettyNValueF = fmap prettyNValueNF . removeEffectsM -prettyNValue :: MonadVar m => NValue m -> m Doc +prettyNValue :: MonadVar m => NValue m -> m (Doc ann) prettyNValue (NValue _ v) = prettyNValueF v -prettyNValueProv :: MonadVar m => NValue m -> m Doc +prettyNValueProv :: MonadVar m => NValue m -> m (Doc ann) prettyNValueProv = \case NValue [] v -> prettyNValueF v NValue ps v -> do v' <- prettyNValueF v - pure $ v' indent 2 (parens (mconcat - (text "from: " : map (prettyOriginExpr . _originExpr) ps))) - -prettyNThunk :: MonadVar m => NThunk m -> m Doc + pure $ fillSep $ + [ v' + , indent 2 $ parens $ mconcat + $ "from: " + : map (prettyOriginExpr . _originExpr) ps + ] +prettyNThunk :: MonadVar m => NThunk m -> m (Doc ann) prettyNThunk = \case t@(NThunk ps _) -> do v' <- fmap prettyNValueNF (dethunk t) - pure $ v' indent 2 (parens (mconcat - (text "thunk from: " : map (prettyOriginExpr . _originExpr) ps))) - + pure $ fillSep $ + [ v' + , indent 2 $ parens $ mconcat + $ "thunk from: " + : map (prettyOriginExpr . _originExpr) ps + ] dethunk :: MonadVar m => NThunk m -> m (NValueNF m) dethunk = \case NThunk _ (Value v) -> removeEffectsM (_baseValue v) @@ -322,4 +349,4 @@ dethunk = \case Computed v -> removeEffectsM (_baseValue v) _ -> pure $ Free $ NVStrF (hackyMakeNixStringWithoutContext "") _ <- atomicModifyVar active (False,) - return res \ No newline at end of file + return res diff --git a/src/Nix/Render.hs b/src/Nix/Render.hs index abf7362..7779f5d 100644 --- a/src/Nix/Render.hs +++ b/src/Nix/Render.hs @@ -12,24 +12,24 @@ module Nix.Render where import Data.ByteString (ByteString) import Data.List.NonEmpty (NonEmpty((:|))) import qualified Data.Set as Set +import Data.Text.Prettyprint.Doc import Data.Void import Nix.Expr.Types.Annotated import Text.Megaparsec.Error import Text.Megaparsec.Pos (SourcePos(..)) -import Text.PrettyPrint.ANSI.Leijen class Monad m => MonadFile m where readFile :: FilePath -> m ByteString -posAndMsg :: SourcePos -> Doc -> ParseError t Void +posAndMsg :: SourcePos -> Doc a-> ParseError t Void posAndMsg beg msg = FancyError (beg :| []) (Set.fromList [ErrorFail (show msg) :: ErrorFancy Void]) -renderLocation :: MonadFile m => SrcSpan -> Doc -> m Doc +renderLocation :: MonadFile m => SrcSpan -> Doc a -> m (Doc a) renderLocation (SrcSpan beg@(SourcePos "" _ _) _) msg = - return $ text $ init $ parseErrorPretty @Char (posAndMsg beg msg) + return $ pretty $ init $ parseErrorPretty @Char (posAndMsg beg msg) renderLocation (SrcSpan beg@(SourcePos path _ _) _) msg = do contents <- Nix.Render.readFile path - return $ text $ init $ parseErrorPretty' contents (posAndMsg beg msg) + return $ pretty $ init $ parseErrorPretty' contents (posAndMsg beg msg) diff --git a/src/Nix/Render/Frame.hs b/src/Nix/Render/Frame.hs index 4c40ff3..fbaae71 100644 --- a/src/Nix/Render/Frame.hs +++ b/src/Nix/Render/Frame.hs @@ -16,6 +16,7 @@ module Nix.Render.Frame where import Control.Monad.Reader import Data.Fix import Data.Typeable +import Data.Text.Prettyprint.Doc import Nix.Eval import Nix.Exec import Nix.Expr @@ -28,16 +29,15 @@ import Nix.Thunk import Nix.Utils import Nix.Value import Text.Megaparsec.Pos -import qualified Text.PrettyPrint.ANSI.Leijen as P -import Text.PrettyPrint.ANSI.Leijen hiding ((<$>)) #ifdef MIN_VERSION_pretty_show import qualified Text.Show.Pretty as PS #endif -renderFrames :: forall v e m. - (MonadReader e m, Has e Options, - MonadVar m, MonadFile m, Typeable m, Typeable v) - => Frames -> m Doc +renderFrames + :: forall v e m ann + . ( MonadReader e m, Has e Options + , MonadVar m, MonadFile m, Typeable m, Typeable v) + => Frames -> m (Doc ann) renderFrames [] = pure mempty renderFrames (x:xs) = do opts :: Options <- asks (view hasLens) @@ -51,13 +51,13 @@ renderFrames (x:xs) = do concat <$> mapM (renderFrame @v) (reverse (x:xs)) pure $ case frames of [] -> mempty - _ -> foldr1 (P.<$>) frames + _ -> vsep frames where - go :: NixFrame -> [Doc] + go :: NixFrame -> [Doc ann] go f = case framePos @v @m f of Just pos -> - [text "While evaluating at " - <> text (sourcePosPretty pos) + ["While evaluating at " + <> pretty (sourcePosPretty pos) <> colon] Nothing -> [] @@ -70,29 +70,29 @@ framePos (NixFrame _ f) _ -> Nothing | otherwise = Nothing -renderFrame :: forall v e m. +renderFrame :: forall v e m ann. (MonadReader e m, Has e Options, MonadVar m, MonadFile m, Typeable m, Typeable v) - => NixFrame -> m [Doc] + => NixFrame -> m [Doc ann] renderFrame (NixFrame level f) | Just (e :: EvalFrame m v) <- fromException f = renderEvalFrame level e | Just (e :: ThunkLoop) <- fromException f = renderThunkLoop level e | Just (e :: ValueFrame m) <- fromException f = renderValueFrame level e | Just (e :: NormalLoop m) <- fromException f = renderNormalLoop level e | Just (e :: ExecFrame m) <- fromException f = renderExecFrame level e - | Just (e :: ErrorCall) <- fromException f = pure [text (show e)] + | Just (e :: ErrorCall) <- fromException f = pure [pretty (show e)] | otherwise = error $ "Unrecognized frame: " ++ show f wrapExpr :: NExprF r -> NExpr wrapExpr x = Fix (Fix (NSym "") <$ x) renderEvalFrame :: (MonadReader e m, Has e Options, MonadFile m) - => NixLevel -> EvalFrame m v -> m [Doc] + => NixLevel -> EvalFrame m v -> m [Doc ann] renderEvalFrame level f = do opts :: Options <- asks (view hasLens) case f of EvaluatingExpr scope e@(Fix (Compose (Ann ann _))) -> do - let scopeInfo | scopes opts = [string (show scope)] + let scopeInfo | scopes opts = [pretty $ show scope] | otherwise = [] fmap (\x -> scopeInfo ++ [x]) $ renderLocation ann =<< renderExpr level "While evaluating" "Expression" e @@ -105,59 +105,64 @@ renderEvalFrame level f = do Calling name ann -> fmap (:[]) $ renderLocation ann $ - text "While calling builtins." <> text name + "While calling builtins." <> pretty name _ -> pure [] renderExpr :: (MonadReader e m, Has e Options, MonadFile m) - => NixLevel -> String -> String -> NExprLoc -> m Doc + => NixLevel -> String -> String -> NExprLoc -> m (Doc ann) renderExpr _level longLabel shortLabel e@(Fix (Compose (Ann _ x))) = do opts :: Options <- asks (view hasLens) let rendered | verbose opts >= DebugInfo = #ifdef MIN_VERSION_pretty_show - text (PS.ppShow (stripAnnotation e)) + pretty (PS.ppShow (stripAnnotation e)) #else - text (show (stripAnnotation e)) + pretty (show (stripAnnotation e)) #endif | verbose opts >= Chatty = prettyNix (stripAnnotation e) | otherwise = prettyNix (Fix (Fix (NSym "") <$ x)) pure $ if verbose opts >= Chatty - then text (longLabel ++ ":\n>>>>>>>>") - P.<$> indent 2 rendered - P.<$> text "<<<<<<<<" - else text shortLabel <> text ": " rendered + then vsep $ + [ pretty (longLabel ++ ":\n>>>>>>>>") + , indent 2 rendered + , "<<<<<<<<" + ] + else pretty shortLabel <> fillSep [": ", rendered] renderValueFrame :: (MonadReader e m, Has e Options, MonadFile m, MonadVar m) - => NixLevel -> ValueFrame m -> m [Doc] + => NixLevel -> ValueFrame m -> m [Doc ann] renderValueFrame level = fmap (:[]) . \case - ForcingThunk -> pure $ text "ForcingThunk" - ConcerningValue _v -> pure $ text "ConcerningValue" - Comparison _ _ -> pure $ text "Comparing" - Addition _ _ -> pure $ text "Adding" - Division _ _ -> pure $ text "Dividing" - Multiplication _ _ -> pure $ text "Multiplying" + ForcingThunk -> pure "ForcingThunk" + ConcerningValue _v -> pure "ConcerningValue" + Comparison _ _ -> pure "Comparing" + Addition _ _ -> pure "Adding" + Division _ _ -> pure "Dividing" + Multiplication _ _ -> pure "Multiplying" - Coercion x y -> - pure $ text desc <> text (describeValue x) - <> text " to " <> text (describeValue y) + Coercion x y -> pure $ mconcat + [ desc + , pretty (describeValue x) + , " to " + , pretty (describeValue y) + ] where desc | level <= Error = "Cannot coerce " | otherwise = "While coercing " - CoercionToJsonNF _v -> pure $ text "CoercionToJsonNF" - CoercionFromJson _j -> pure $ text "CoercionFromJson" - ExpectationNF _t _v -> pure $ text "ExpectationNF" + CoercionToJsonNF _v -> pure "CoercionToJsonNF" + CoercionFromJson _j -> pure "CoercionFromJson" + ExpectationNF _t _v -> pure "ExpectationNF" Expectation t v -> do v' <- renderValue level "" "" v - pure $ text "Saw " <> v' - <> text " but expected " <> text (describeValue t) + pure $ "Saw " <> v' + <> " but expected " <> pretty (describeValue t) renderValue :: (MonadReader e m, Has e Options, MonadFile m, MonadVar m) - => NixLevel -> String -> String -> NValue m -> m Doc + => NixLevel -> String -> String -> NValue m -> m (Doc ann) renderValue _level _longLabel _shortLabel v = do opts :: Options <- asks (view hasLens) if values opts @@ -165,23 +170,23 @@ renderValue _level _longLabel _shortLabel v = do else prettyNValue v renderExecFrame :: (MonadReader e m, Has e Options, MonadVar m, MonadFile m) - => NixLevel -> ExecFrame m -> m [Doc] + => NixLevel -> ExecFrame m -> m [Doc ann] renderExecFrame level = \case Assertion ann v -> fmap (:[]) $ renderLocation ann - =<< ((text "Assertion failed:" ) + =<< ((\d -> fillSep ["Assertion failed:", d]) <$> renderValue level "" "" v) renderThunkLoop :: (MonadReader e m, Has e Options, MonadFile m) - => NixLevel -> ThunkLoop -> m [Doc] + => NixLevel -> ThunkLoop -> m [Doc ann] renderThunkLoop _level = pure . (:[]) . \case - ThunkLoop Nothing -> text "<>" + ThunkLoop Nothing -> "<>" ThunkLoop (Just n) -> - text $ "<>" + pretty $ "<>" renderNormalLoop :: (MonadReader e m, Has e Options, MonadFile m, MonadVar m) - => NixLevel -> NormalLoop m -> m [Doc] + => NixLevel -> NormalLoop m -> m [Doc ann] renderNormalLoop level = fmap (:[]) . \case NormalLoop v -> do v' <- renderValue level "" "" v - pure $ text "< v' <> text ">>" + pure $ "< v' <> ">>" diff --git a/tests/ParserTests.hs b/tests/ParserTests.hs index 639bed2..307b3ae 100644 --- a/tests/ParserTests.hs +++ b/tests/ParserTests.hs @@ -12,7 +12,9 @@ import Data.Fix import Data.List.NonEmpty (NonEmpty(..)) import Data.Semigroup import Data.String.Interpolate.IsString -import Data.Text (Text, unpack, pack) +import Data.Text (Text, unpack) +import Data.Text.Prettyprint.Doc +import Data.Text.Prettyprint.Doc.Render.Text import Nix.Atoms import Nix.Expr import Nix.Parser @@ -20,7 +22,6 @@ import Nix.Pretty import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.TH -import Text.PrettyPrint.ANSI.Leijen hiding ((<$>), (<>)) case_constant_int = assertParseText "234" $ mkInt 234 @@ -394,9 +395,9 @@ assertParseFail str = case parseNixText str of assertParsePrint :: Text -> Text -> Assertion assertParsePrint src expect = let Success expr = parseNixTextLoc src - result = displayS - . renderPretty 0.4 80 + result = renderStrict + . layoutPretty (LayoutOptions $ AvailablePerLine 80 0.4) . prettyNix . stripAnnotation $ expr - in assertEqual "" expect (pack (result "")) + in assertEqual "" expect result diff --git a/tests/PrettyParseTests.hs b/tests/PrettyParseTests.hs index c219e11..a50ca50 100644 --- a/tests/PrettyParseTests.hs +++ b/tests/PrettyParseTests.hs @@ -17,6 +17,7 @@ import Data.Char import Data.Fix import qualified Data.List.NonEmpty as NE import Data.Text (Text, pack) +import Data.Text.Prettyprint.Doc import Hedgehog import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range @@ -27,8 +28,6 @@ import Nix.Pretty import Test.Tasty import Test.Tasty.Hedgehog import Text.Megaparsec (Pos, SourcePos, mkPos) -import Text.PrettyPrint.ANSI.Leijen ((), text) -import qualified Text.PrettyPrint.ANSI.Leijen as P import qualified Text.Show.Pretty as PS asciiString :: MonadGen m => m String @@ -188,38 +187,38 @@ normalize = cata $ \case -- | Test that parse . pretty == id up to attribute position information. prop_prettyparse :: Monad m => NExpr -> PropertyT m () prop_prettyparse p = do - let prog = show (pretty p) + let prog = show (prettyNix p) case parse (pack prog) of Failure s -> do - footnote $ show $ - text "Parse failed:" text (show s) - P.<$> P.indent 2 (pretty p) + footnote $ show $ vsep + [ fillSep ["Parse failed:", pretty (show s)] + , indent 2 (prettyNix p) + ] discard Success v | equivUpToNormalization p v -> success | otherwise -> do let pp = normalise prog - pv = normalise (show (pretty v)) - footnote $ show $ - text "----------------------------------------" - P.<$> text "Expr before:" P.<$> P.indent 2 (text (PS.ppShow p)) - P.<$> text "----------------------------------------" - P.<$> text "Expr after:" P.<$> P.indent 2 (text (PS.ppShow v)) - P.<$> text "----------------------------------------" - P.<$> text "Pretty before:" P.<$> P.indent 2 (text prog) - P.<$> text "----------------------------------------" - P.<$> text "Pretty after:" P.<$> P.indent 2 (pretty v) - P.<$> text "----------------------------------------" - P.<$> text "Normalised before:" P.<$> P.indent 2 (text pp) - P.<$> text "----------------------------------------" - P.<$> text "Normalised after:" P.<$> P.indent 2 (text pv) - P.<$> text "========================================" - P.<$> text "Normalised diff:" - P.<$> text (ppDiff (diff pp pv)) - P.<$> text "========================================" + pv = normalise (show (prettyNix v)) + footnote $ show $ vsep $ + [ "----------------------------------------" + , vsep ["Expr before:", indent 2 (pretty (PS.ppShow p))] + , "----------------------------------------" + , vsep ["Expr after:", indent 2 (pretty (PS.ppShow v))] + , "----------------------------------------" + , vsep ["Pretty before:", indent 2 (pretty prog)] + , "----------------------------------------" + , vsep ["Pretty after:", indent 2 (prettyNix v)] + , "----------------------------------------" + , vsep ["Normalised before:", indent 2 (pretty pp)] + , "----------------------------------------" + , vsep ["Normalised after:", indent 2 (pretty pv)] + , "========================================" + , vsep ["Normalised diff:", pretty (ppDiff (diff pp pv))] + , "========================================" + ] assert (pp == pv) where - pretty = prettyNix parse = parseNixText normalise = unlines . map (reverse . dropWhile isSpace . reverse) . lines