packages feed

pretty-diff (empty) → 0.1.0.0

raw patch · 6 files changed

+479/−0 lines, 6 filesdep +Diffdep +basedep +data-default

Dependencies added: Diff, base, data-default, pretty-diff, tasty, tasty-hunit, tasty-test-reporter, text

Files

+ CHANGELOG.md view
@@ -0,0 +1,3 @@+# 0.1.0.0++- Initial implementation.
+ LICENSE view
@@ -0,0 +1,29 @@+BSD 3-Clause License++Copyright (c) 2020, Christoph Hermann+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+   list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+   this list of conditions and the following disclaimer in the documentation+   and/or other materials provided with the distribution.++3. Neither the name of the copyright holder nor the names of its+   contributors may be used to endorse or promote products derived from+   this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,23 @@+# pretty-diff++Pretty printing a diff of two values.++## Usage++```hs+import qualified Pretty.Diff as Diff+import Data.Default (def)++Diff.pretty def "1234" "_23"+```+Will create a string that looks like this:++```+ ▼ ▼+"1234"+╷+│+╵+"_23"+ ▲+```
+ pretty-diff.cabal view
@@ -0,0 +1,62 @@+cabal-version: 1.18++-- This file has been generated from package.yaml by hpack version 0.33.0.+--+-- see: https://github.com/sol/hpack+--+-- hash: 4f4d19546099374e472ed7d6dd40094526c70cb5b1e0b7c2033232726b349f95++name:           pretty-diff+version:        0.1.0.0+synopsis:       Pretty printing a simple diff of two values.+description:    Please see the README at <https://github.com/stoeffel/pretty-diff>.+category:       Diffing+homepage:       https://github.com/stoeffel/pretty-diff#readme+bug-reports:    https://github.com/stoeffel/pretty-diff/issues+author:         Christoph Hermann+maintainer:     schtoeffel@gmail.com+copyright:      2020 Christoph Hermann+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-doc-files:+    README.md+    CHANGELOG.md++source-repository head+  type: git+  location: https://github.com/stoeffel/pretty-diff++library+  exposed-modules:+      Pretty.Diff+  other-modules:+      Paths_pretty_diff+  hs-source-dirs:+      src+  build-depends:+      Diff >=0.3 && <0.4+    , base >=4.10.1.0 && <5+    , data-default >=0.7 && <0.8+    , text >=1.2 && <1.3+  default-language: Haskell2010++test-suite spec+  type: exitcode-stdio-1.0+  main-is: Main.hs+  other-modules:+      Pretty.Diff+      Paths_pretty_diff+  hs-source-dirs:+      test+      src+  build-depends:+      Diff >=0.3 && <0.4+    , base+    , data-default >=0.7 && <0.8+    , pretty-diff+    , tasty >=1.1 && <1.3+    , tasty-hunit+    , tasty-test-reporter+    , text >=1.2 && <1.3+  default-language: Haskell2010
+ src/Pretty/Diff.hs view
@@ -0,0 +1,189 @@+{-# LANGUAGE NamedFieldPuns #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Printing nice and simple diffs of two values.+--+-- @+-- import qualified Pretty.Diff as Diff+-- import Data.Default (def)+--+-- Diff.pretty def "1234" "_23"+-- @+--+-- Will create a string that looks like this:+--+-- @+--  ▼ ▼+-- "1234"+-- ╷+-- │+-- ╵+-- "_23"+--  ▲+-- @+module Pretty.Diff+  ( -- * Configuration+    Config (Config, separatorText, wrapping),+    Wrapping (Wrap, NoWrap),++    -- * pretty printing+    pretty,+    actual,+    expected,+  )+where++import qualified Data.Algorithm.Diff as Diff+import Data.Default (Default, def)+import Data.Function ((&))+import Data.List (transpose)+import Data.Maybe (fromMaybe, mapMaybe)+import Data.String (IsString)+import qualified Data.Text as Text+import Data.Text (Text)+import Prelude++-- | Configuration for `Pretty.Diff.pretty`.+data Config+  = Config+      { -- | Text that gets displayed inbetween the diffed values+        --+        -- @+        -- Diff.pretty def { Diff.separatorText = "differing" } "1234" "_23"+        -- @+        --+        -- Will create a string that looks like this:+        --+        -- @+        --  ▼ ▼+        -- "1234"+        -- ╷+        -- │ differing+        -- ╵+        -- "_23"+        --  ▲+        -- @+        separatorText :: Maybe Text,+        -- | Wrapping text to multiple lines if they are longer than the provided length.+        -- This is useful in combination with [terminal-size](https://hackage.haskell.org/package/terminal-size).+        --+        -- @+        -- Diff.pretty def { Diff.wrapping = Diff.Wrap 6 } "0900000000" "9000000000"+        -- @+        --+        -- Will create a string that looks like this:+        --+        -- @+        --  ▼+        -- "09000+        -- 00000"+        -- ╷+        -- │+        -- ╵+        -- "90000+        -- 00000"+        --     ▲+        -- @+        wrapping :: Wrapping+      }++instance Default Config where+  def = Config {separatorText = Nothing, wrapping = NoWrap}++-- | Define whether or not to wrap the diffing lines.+data Wrapping+  = Wrap Int+  | NoWrap++-- | Printing a full diff of both values separated by some pipes.+pretty :: Show a => Config -> a -> a -> Text+pretty Config {separatorText, wrapping} x y =+  [ actual wrapping x y,+    separator separatorText,+    expected wrapping x y+  ]+    & mconcat++-- | Printing The first value and the diff indicator above.+--+--  @+--  Diff.actual Diff.NoWrap "1234" "_23"+--  @+--+--  @+--  ▼ ▼+-- "1234"+--  @+actual :: Show a => Wrapping -> a -> a -> Text+actual wrapping x y =+  wrap wrapping [diffLine First down x y, Text.pack (show x)]+    & filterEmptyLines+    & Text.unlines++-- | Printing The second value and the diff indicator below.+--+--  @+--  Diff.expected Diff.NoWrap "1234" "_23"+--  @+--+--  @+-- "_23"+--  ▲+--  @+expected :: Show a => Wrapping -> a -> a -> Text+expected wrapping x y =+  wrap wrapping [Text.pack (show y), diffLine Second up x y]+    & filterEmptyLines+    & Text.unlines++wrap :: Wrapping -> [Text] -> [Text]+wrap wrapping text =+  case wrapping of+    Wrap n ->+      text+        & fmap (Text.chunksOf n)+        & interleaveLists+    NoWrap -> text++down :: Char+down = '▼'++up :: Char+up = '▲'++data Position = First | Second++diffLine :: Show a => Position -> Char -> a -> a -> Text.Text+diffLine pos differ a b =+  Diff.getDiff+    (show a)+    (show b)+    & mapMaybe (toDiffLine pos differ)+    & Text.pack+    & Text.stripEnd++toDiffLine :: Position -> Char -> Diff.Diff a -> Maybe Char+toDiffLine pos c d =+  case d of+    Diff.First _ -> case pos of+      First -> Just c+      Second -> Nothing+    Diff.Second _ -> case pos of+      First -> Nothing+      Second -> Just c+    Diff.Both _ _ -> Just ' '++separator :: Maybe Text -> Text+separator maybeComparison =+  [ "╷",+    "│" <> (fromMaybe "" $ ((<>) " ") <$> maybeComparison),+    "╵"+  ]+    & Text.unlines++interleaveLists :: [[a]] -> [a]+interleaveLists = mconcat . transpose++filterEmptyLines :: [Text] -> [Text]+filterEmptyLines = filter (not . Text.null . Text.strip)
+ test/Main.hs view
@@ -0,0 +1,173 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Main+  ( main,+  )+where++import Control.Exception (catch, throw)+import Data.Default (def)+import Data.Function ((&))+import qualified Data.Text as Text+import qualified Data.Text.IO as Text.IO+import qualified Pretty.Diff as Diff+import Test.Tasty+import Test.Tasty.HUnit+import qualified Test.Tasty.Runners.Reporter as Reporter++main = defaultMainWithIngredients [Reporter.ingredient] tests++tests :: TestTree+tests =+  testGroup+    "Pretty.Diff"+    [ testCase "Comparing two equal strings" $+        expectDiffToEqual+          ( Diff.pretty+              def+              "Hello"+              "Hello"+          )+          [ "Hello" & showText,+            "╷",+            "│",+            "╵",+            "Hello" & showText+          ],+      testCase "Removed characters" $+        expectDiffToEqual+          ( Diff.pretty+              def+              "Hello"+              "Hel"+          )+          [ "   ▼▼" & forEscapedString,+            "Hello" & showText,+            "╷",+            "│",+            "╵",+            "Hel" & showText+          ],+      testCase "Added characters" $+        expectDiffToEqual+          ( Diff.pretty+              def+              "Hel"+              "Hello"+          )+          [ "Hel" & showText,+            "╷",+            "│",+            "╵",+            "Hello" & showText,+            "   ▲▲" & forEscapedString+          ],+      testCase "Changed characters" $+        expectDiffToEqual+          ( Diff.pretty+              def+              "Axxx"+              "Bxxx"+          )+          [ "▼" & forEscapedString,+            "Axxx" & showText,+            "╷",+            "│",+            "╵",+            "Bxxx" & showText,+            "▲" & forEscapedString+          ],+      testCase "Mixed changes" $+        expectDiffToEqual+          ( Diff.pretty+              def+              "12345"+              "1004"+          )+          [ " ▼▼ ▼" & forEscapedString,+            "12345" & showText,+            "╷",+            "│",+            "╵",+            "1004" & showText,+            " ▲▲" & forEscapedString+          ],+      testCase "Multiline changes (on first and last line)" $+        expectDiffToEqual+          ( Diff.pretty+              def+                { Diff.wrapping = Diff.Wrap $ 5 + 1 -- + 1 because of "+                }+              "0900000000"+              "9000000000"+          )+          [ "▼" & forEscapedString,+            "09000" & showTextPrefix,+            "00000" & showTextPostfix,+            "╷",+            "│",+            "╵",+            "90000" & showTextPrefix,+            "00000" & showTextPostfix,+            "    ▲"+          ],+      testCase "Multiline changes (inbetween)" $+        expectDiffToEqual+          ( Diff.pretty+              def+                { Diff.wrapping = Diff.Wrap $ 5 + 1 -- + 1 because of "+                }+              "0000090000"+              "0090000000"+          )+          [ "00000" & showTextPrefix,+            "▼",+            "90000" & showTextPostfix,+            "╷",+            "│",+            "╵",+            "00900" & showTextPrefix,+            "  ▲" & forEscapedString,+            "00000" & showTextPostfix+          ],+      testCase "With separator text" $+        expectDiffToEqual+          ( Diff.pretty+              Diff.Config+                { Diff.separatorText = Just "equals",+                  Diff.wrapping = Diff.Wrap $ 5 + 1 -- + 1 because of "+                }+              "0000090000"+              "0090000000"+          )+          [ "00000" & showTextPrefix,+            "▼",+            "90000" & showTextPostfix,+            "╷",+            "│ equals",+            "╵",+            "00900" & showTextPrefix,+            "  ▲" & forEscapedString,+            "00000" & showTextPostfix+          ]+    ]++expectDiffToEqual actual expected_ = do+  let expected = Text.unlines expected_+  (actual @?= expected)+    `catch` ( \(e :: HUnitFailure) -> do+                Text.IO.putStrLn "Actual was:"+                Text.IO.putStrLn actual+                Text.IO.putStrLn "Expected was:"+                Text.IO.putStrLn expected+                throw e+            )++forEscapedString x = " " <> x++showText = Text.pack . show++showTextPrefix x = "\"" <> x++showTextPostfix x = x <> "\""