From 47407aca324c7e33158e68e40946229c45492c5b Mon Sep 17 00:00:00 2001 From: Oleg Grenrus Date: Tue, 12 May 2026 22:47:50 +0300 Subject: [PATCH] Use prettyprinter directly --- .github/workflows/haskell-ci.yml | 26 ++++++++--- ChangeLog.md | 7 +++ src/Data/TreeDiff/Golden.hs | 18 +++++--- src/Data/TreeDiff/Pretty.hs | 74 ++++++++++++++++++++------------ src/Data/TreeDiff/QuickCheck.hs | 9 +++- tests/Tests.hs | 14 +++--- tree-diff.cabal | 37 ++++++++-------- 7 files changed, 117 insertions(+), 68 deletions(-) diff --git a/.github/workflows/haskell-ci.yml b/.github/workflows/haskell-ci.yml index bb506c7..6749a57 100644 --- a/.github/workflows/haskell-ci.yml +++ b/.github/workflows/haskell-ci.yml @@ -8,9 +8,9 @@ # # For more information, see https://github.com/haskell-CI/haskell-ci # -# version: 0.19.20250708 +# version: 0.19.20260331 # -# REGENDATA ("0.19.20250708",["github","cabal.project"]) +# REGENDATA ("0.19.20260331",["github","cabal.project"]) # name: Haskell-CI on: @@ -20,6 +20,11 @@ on: pull_request: branches: - master + merge_group: + branches: + - master + workflow_dispatch: + {} jobs: linux: name: Haskell-CI - Linux - ${{ matrix.compiler }} @@ -32,14 +37,19 @@ jobs: strategy: matrix: include: + - compiler: ghc-9.14.1 + compilerKind: ghc + compilerVersion: 9.14.1 + setup-method: ghcup + allow-failure: false - compiler: ghc-9.12.2 compilerKind: ghc compilerVersion: 9.12.2 setup-method: ghcup allow-failure: false - - compiler: ghc-9.10.2 + - compiler: ghc-9.10.3 compilerKind: ghc - compilerVersion: 9.10.2 + compilerVersion: 9.10.3 setup-method: ghcup allow-failure: false - compiler: ghc-9.8.4 @@ -95,8 +105,8 @@ jobs: chmod a+x "$HOME/.ghcup/bin/ghcup" - name: Install cabal-install run: | - "$HOME/.ghcup/bin/ghcup" install cabal 3.14.2.0 || (cat "$HOME"/.ghcup/logs/*.* && false) - echo "CABAL=$HOME/.ghcup/bin/cabal-3.14.2.0 -vnormal+nowrap" >> "$GITHUB_ENV" + "$HOME/.ghcup/bin/ghcup" install cabal 3.16.0.0 || (cat "$HOME"/.ghcup/logs/*.* && false) + echo "CABAL=$HOME/.ghcup/bin/cabal-3.16.0.0 -vnormal+nowrap" >> "$GITHUB_ENV" - name: Install GHC (GHCup) if: matrix.setup-method == 'ghcup' run: | @@ -181,7 +191,7 @@ jobs: chmod a+x $HOME/.cabal/bin/cabal-docspec cabal-docspec --version - name: checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: path: source - name: initial cabal.project for sdist @@ -209,6 +219,8 @@ jobs: echo " ghc-options: -Werror=missing-methods -Werror=missing-fields" >> cabal.project if [ $((HCNUMVER >= 90400)) -ne 0 ] ; then echo "package tree-diff" >> cabal.project ; fi if [ $((HCNUMVER >= 90400)) -ne 0 ] ; then echo " ghc-options: -Werror=unused-packages" >> cabal.project ; fi + if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then echo "package tree-diff" >> cabal.project ; fi + if [ $((HCNUMVER >= 90000)) -ne 0 ] ; then echo " ghc-options: -Werror=incomplete-patterns -Werror=incomplete-uni-patterns" >> cabal.project ; fi cat >> cabal.project <> cabal.project.local diff --git a/ChangeLog.md b/ChangeLog.md index 1a0621c..6067903 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,10 @@ +## 0.4 + +- Drop `ansi-wl-pprint` dependency, use `prettyprinter` directly. + The naming of functions still uses `ansiWl*` naming scheme, to avoid breaking + too many things. Technically, these functions are still compatible with + `ansi-wl-pprint` versions which use `prettyprinter` underneath. + ## 0.3.4 - Remove 'Eq a' requirement from 'ediffGolden'. The constraint wasn't used, as we only compare 'Expr' representations. diff --git a/src/Data/TreeDiff/Golden.hs b/src/Data/TreeDiff/Golden.hs index f21f19a..bceb8f4 100644 --- a/src/Data/TreeDiff/Golden.hs +++ b/src/Data/TreeDiff/Golden.hs @@ -10,10 +10,12 @@ import System.Console.ANSI (SGR (Reset), setSGRCode) import Text.Parsec (eof, parse) import Text.Parsec.Text () -import qualified Data.ByteString as BS -import qualified Data.Text as T -import qualified Data.Text.Encoding as TE -import qualified Text.PrettyPrint.ANSI.Leijen as WL +import qualified Data.ByteString as BS +import qualified Data.Text as T +import qualified Data.Text.Encoding as TE +import qualified Data.Text.Lazy as TL +import qualified Prettyprinter as PP +import qualified Prettyprinter.Render.Terminal as PP.A -- | Make a golden tests. -- @@ -74,7 +76,9 @@ ediffGolden1 impl testName fp x = impl testName expect actual cmp wrt | a == b = return Nothing | otherwise = return $ Just $ setSGRCode [Reset] ++ showWL (ansiWlEditExprCompact $ ediff a b) - wrt expr = BS.writeFile fp $ TE.encodeUtf8 $ T.pack $ showWL (WL.plain (ansiWlExpr expr)) ++ "\n" + wrt expr = BS.writeFile fp $ TE.encodeUtf8 $ T.pack $ showWL (PP.unAnnotate (ansiWlExpr expr)) ++ "\n" -showWL :: WL.Doc -> String -showWL doc = WL.displayS (WL.renderSmart 0.4 80 doc) "" +showWL :: PP.Doc PP.A.AnsiStyle -> String +showWL doc + = TL.unpack $ PP.A.renderLazy + $ PP.layoutSmart PP.LayoutOptions { PP.layoutPageWidth = PP.AvailablePerLine 80 0.4 } doc diff --git a/src/Data/TreeDiff/Pretty.hs b/src/Data/TreeDiff/Pretty.hs index f66208a..38f1e8b 100644 --- a/src/Data/TreeDiff/Pretty.hs +++ b/src/Data/TreeDiff/Pretty.hs @@ -10,7 +10,7 @@ module Data.TreeDiff.Pretty ( prettyExpr, prettyEditExpr, prettyEditExprCompact, - -- * ansi-wl-pprint + -- * prettyprinter ansiWlPretty, ansiWlExpr, ansiWlEditExpr, @@ -30,9 +30,10 @@ import Data.TreeDiff.Expr import Numeric (showHex) import Text.Read (readMaybe) -import qualified Data.TreeDiff.OMap as OMap -import qualified Text.PrettyPrint as HJ -import qualified Text.PrettyPrint.ANSI.Leijen as WL +import qualified Data.TreeDiff.OMap as OMap +import qualified Prettyprinter as PP +import qualified Prettyprinter.Render.Terminal as PP.A +import qualified Text.PrettyPrint as HJ -- $setup -- >>> import qualified Data.TreeDiff.OMap as OMap @@ -215,56 +216,73 @@ prettyEditExprCompact = ppEditExprCompact prettyPretty -- ansi-wl-pprint ------------------------------------------------------------------------------- --- | 'Pretty' via @ansi-wl-pprint@ library (with colors). -ansiWlPretty :: Pretty WL.Doc +-- | 'Pretty' via @prettyprinter@ library (with colors). +ansiWlPretty :: Pretty (PP.Doc PP.A.AnsiStyle) ansiWlPretty = Pretty - { ppCon = WL.text - , ppRec = \c xs -> ansiGroup (c WL.<+> WL.lbrace) WL.rbrace - $ map (\(fn, d) -> WL.text fn WL.<+> WL.equals WL. d) xs - , ppLst = ansiGroup WL.lbracket WL.rbracket - , ppCpy = WL.dullwhite - , ppIns = \d -> WL.green $ WL.plain $ WL.char '+' WL.<> d - , ppDel = \d -> WL.red $ WL.plain $ WL.char '-' WL.<> d - , ppApp = \f xs -> WL.group $ WL.nest 2 $ f WL.<$> WL.vsep xs - , ppEdits = WL.sep - , ppEllip = WL.text "..." - , ppParens = WL.parens + { ppCon = ppText + , ppRec = \c xs -> ansiGroup (c PP.<+> PP.lbrace) PP.rbrace + $ map (\(fn, d) -> ppText fn PP.<+> (PP.equals PP.<> PP.softline PP.<> d)) xs + , ppLst = ansiGroup PP.lbracket PP.rbracket + , ppCpy = ppDullWhite + , ppIns = \d -> ppGreen $ PP.unAnnotate $ ppChar '+' PP.<> d + , ppDel = \d -> ppRed $ PP.unAnnotate $ ppChar '-' PP.<> d + , ppApp = \f xs -> PP.group $ PP.nest 2 $ f PP.<> PP.line PP.<> PP.vsep xs + , ppEdits = PP.sep + , ppEllip = ppText "..." + , ppParens = PP.parens } -ansiGroup :: WL.Doc -> WL.Doc -> [WL.Doc] -> WL.Doc -ansiGroup l r xs = WL.group $ WL.nest 2 (l WL.<$$> WL.vsep (WL.punctuate WL.comma xs) WL.<> r) +ansiGroup :: PP.Doc PP.A.AnsiStyle -> PP.Doc PP.A.AnsiStyle -> [PP.Doc PP.A.AnsiStyle] -> PP.Doc PP.A.AnsiStyle +ansiGroup l r xs = PP.group $ PP.nest 2 (l PP.<> ppLinebreak PP.<> PP.vsep (PP.punctuate PP.comma xs) PP.<> r) -- | Pretty print 'Expr' using @ansi-wl-pprint@. -ansiWlExpr :: Expr -> WL.Doc +ansiWlExpr :: Expr -> PP.Doc PP.A.AnsiStyle ansiWlExpr = ppExpr ansiWlPretty -- | Pretty print @'Edit' 'EditExpr'@ using @ansi-wl-pprint@. -ansiWlEditExpr :: Edit EditExpr -> WL.Doc +ansiWlEditExpr :: Edit EditExpr -> PP.Doc PP.A.AnsiStyle ansiWlEditExpr = ppEditExpr ansiWlPretty -- | Compact 'ansiWlEditExpr' -ansiWlEditExprCompact :: Edit EditExpr -> WL.Doc +ansiWlEditExprCompact :: Edit EditExpr -> PP.Doc PP.A.AnsiStyle ansiWlEditExprCompact = ppEditExprCompact ansiWlPretty +ppChar :: Char -> PP.Doc PP.A.AnsiStyle +ppChar = PP.pretty + +ppText :: String -> PP.Doc PP.A.AnsiStyle +ppText = PP.pretty + +ppLinebreak :: PP.Doc a +ppLinebreak = PP.flatAlt PP.line mempty + +ppWhite, ppDullWhite, ppRed, ppGreen, ppOnDullRed, ppOnDullGreen :: PP.Doc PP.A.AnsiStyle -> PP.Doc PP.A.AnsiStyle +ppWhite = PP.annotate (PP.A.color PP.A.White) +ppDullWhite = PP.annotate (PP.A.colorDull PP.A.White) +ppRed = PP.annotate (PP.A.color PP.A.Red) +ppGreen = PP.annotate (PP.A.color PP.A.Green) +ppOnDullRed = PP.annotate (PP.A.bgColorDull PP.A.Red) +ppOnDullGreen = PP.annotate (PP.A.bgColorDull PP.A.Green) + ------------------------------------------------------------------------------- -- Background ------------------------------------------------------------------------------- -- | Like 'ansiWlPretty' but color the background. -ansiWlBgPretty :: Pretty WL.Doc +ansiWlBgPretty :: Pretty (PP.Doc PP.A.AnsiStyle) ansiWlBgPretty = ansiWlPretty - { ppIns = \d -> WL.ondullgreen $ WL.white $ WL.plain $ WL.char '+' WL.<> d - , ppDel = \d -> WL.ondullred $ WL.white $ WL.plain $ WL.char '-' WL.<> d + { ppIns = \d -> ppOnDullGreen $ ppWhite $ PP.unAnnotate $ ppChar '+' PP.<> d + , ppDel = \d -> ppOnDullRed $ ppWhite $ PP.unAnnotate $ ppChar '-' PP.<> d } -- | Pretty print 'Expr' using @ansi-wl-pprint@. -ansiWlBgExpr :: Expr -> WL.Doc +ansiWlBgExpr :: Expr -> PP.Doc PP.A.AnsiStyle ansiWlBgExpr = ppExpr ansiWlBgPretty -- | Pretty print @'Edit' 'EditExpr'@ using @ansi-wl-pprint@. -ansiWlBgEditExpr :: Edit EditExpr -> WL.Doc +ansiWlBgEditExpr :: Edit EditExpr -> PP.Doc PP.A.AnsiStyle ansiWlBgEditExpr = ppEditExpr ansiWlBgPretty -- | Compact 'ansiWlBgEditExpr'. -ansiWlBgEditExprCompact :: Edit EditExpr -> WL.Doc +ansiWlBgEditExprCompact :: Edit EditExpr -> PP.Doc PP.A.AnsiStyle ansiWlBgEditExprCompact = ppEditExprCompact ansiWlBgPretty diff --git a/src/Data/TreeDiff/QuickCheck.hs b/src/Data/TreeDiff/QuickCheck.hs index 205dc8f..2c70c3e 100644 --- a/src/Data/TreeDiff/QuickCheck.hs +++ b/src/Data/TreeDiff/QuickCheck.hs @@ -7,8 +7,15 @@ import Data.TreeDiff import System.Console.ANSI (SGR (Reset), setSGRCode) import Test.QuickCheck (Property, counterexample) +import qualified Data.Text.Lazy as TL +import qualified Prettyprinter as PP +import qualified Prettyprinter.Render.Terminal as PP.A + -- | A variant of '===', which outputs a diff when values are inequal. ediffEq :: (Eq a, ToExpr a) => a -> a -> Property ediffEq x y = counterexample - (setSGRCode [Reset] ++ show (ansiWlEditExpr $ ediff x y)) + (setSGRCode [Reset] ++ render (ansiWlEditExpr $ ediff x y)) (x == y) + +render :: PP.Doc PP.A.AnsiStyle -> String +render = TL.unpack . PP.A.renderLazy . PP.layoutPretty PP.defaultLayoutOptions diff --git a/tests/Tests.hs b/tests/Tests.hs index 067a2ea..c331376 100644 --- a/tests/Tests.hs +++ b/tests/Tests.hs @@ -10,12 +10,12 @@ import Test.Tasty (TestTree, defaultMain, testGroup) import Test.Tasty.Golden.Advanced (goldenTest) import Test.Tasty.QuickCheck (testProperty) -import qualified Data.HashSet as HS -import qualified Data.Primitive as Prim -import qualified Text.Parsec as P -import qualified Text.PrettyPrint.ANSI.Leijen as WL -import qualified Text.Trifecta as T (eof, parseString) -import qualified Text.Trifecta.Result as T (ErrInfo (..), Result (..)) +import qualified Data.HashSet as HS +import qualified Data.Primitive as Prim +import qualified Prettyprinter as PP +import qualified Text.Parsec as P +import qualified Text.Trifecta as T (eof, parseString) +import qualified Text.Trifecta.Result as T (ErrInfo (..), Result (..)) import Data.TreeDiff import Data.TreeDiff.Golden @@ -73,7 +73,7 @@ roundtripTrifectaPretty e = counterexample info $ ediffEq (Just e) res' roundtripParsecAnsiWl :: Expr -> Property roundtripParsecAnsiWl e = counterexample info $ ediffEq (Just e) res' where - doc = show (WL.plain (ansiWlExpr e)) + doc = show (PP.unAnnotate (ansiWlExpr e)) res = P.parse (exprParser <* P.eof) "" doc info = case res of diff --git a/tree-diff.cabal b/tree-diff.cabal index 116dd6b..9608c39 100644 --- a/tree-diff.cabal +++ b/tree-diff.cabal @@ -1,6 +1,6 @@ cabal-version: 2.2 name: tree-diff -version: 0.3.5 +version: 0.4 synopsis: Diffing of (expression) trees. category: Data, Testing description: @@ -94,24 +94,25 @@ library , parsec ^>=3.1.13.0 , pretty ^>=1.1.1.0 , text ^>=1.2.3.0 || ^>=2.0 || ^>=2.1 - , time ^>=1.8.0.2 || ^>=1.9.3 || ^>=1.10 || ^>=1.11 || ^>=1.12 || ^>=1.14 || ^>=1.16 + , time ^>=1.8.0.2 || ^>=1.9.3 || ^>=1.10 || ^>=1.11 || ^>=1.12 || ^>=1.14 || ^>=1.15 build-depends: - , aeson ^>=2.2.0.0 - , ansi-terminal ^>=1.1 - , ansi-wl-pprint ^>=1.0.2 || ^>=1.1.1 - , hashable ^>=1.4.4.0 || ^>=1.5.0.0 - , parsers ^>=0.12.11 - , primitive ^>=0.9.0.0 - , QuickCheck ^>=2.14.2 || ^>=2.15 || ^>=2.16.0.0 || ^>=2.18.0.0 - , scientific ^>=0.3.8.0 - , semialign ^>=1.3.1 || ^>=1.4 - , strict ^>=0.5 - , tagged ^>=0.8.8 - , these ^>=1.2.1 - , unordered-containers ^>=0.2.20 - , uuid-types ^>=1.0.6 - , vector ^>=0.13.1.0 + , aeson ^>=2.2.0.0 + , ansi-terminal ^>=1.1 + , hashable ^>=1.4.4.0 || ^>=1.5.0.0 + , parsers ^>=0.12.11 + , prettyprinter ^>=1.7.2 + , prettyprinter-ansi-terminal ^>=1.1.4 + , primitive ^>=0.9.0.0 + , QuickCheck ^>=2.14.2 || ^>=2.15 || ^>=2.16.0.0 || ^>=2.18.0.0 + , scientific ^>=0.3.8.0 + , semialign ^>=1.3.1 || ^>=1.4 + , strict ^>=0.5 + , tagged ^>=0.8.8 + , these ^>=1.2.1 + , unordered-containers ^>=0.2.20 + , uuid-types ^>=1.0.6 + , vector ^>=0.13.1.0 other-extensions: CPP @@ -136,9 +137,9 @@ test-suite tree-diff-test -- dependencies from library build-depends: - , ansi-wl-pprint , base , parsec + , prettyprinter , primitive , QuickCheck , tree-diff