packages feed

pretty-diff 0.2.0.3 → 0.3.0.0

raw patch · 4 files changed

+370/−196 lines, 4 files

Files

CHANGELOG.md view
@@ -1,3 +1,8 @@+# 0.3.0.0++- `pretty/above/below` take `Text` instead of `Show a` allowing the user to decide how to turn stuff into a string.+- Add `prettyMultilines` to render multiline input.+ # 0.2.0.3  - Relax version bounds to support `tasty-1.4`
pretty-diff.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 98c3c2b107783295340487cd6c2daf7788c7660e79fc169f7701b57b33c5fd28+-- hash: b037055a0de30dc728cde0c1b44091182200bbc9adf3ae7ef583d2d6495921c4  name:           pretty-diff-version:        0.2.0.3+version:        0.3.0.0 synopsis:       Pretty printing a diff of two values. description:    Please see the README at <https://github.com/stoeffel/pretty-diff>. category:       Diffing
src/Pretty/Diff.hs view
@@ -26,9 +26,11 @@   ( -- * Configuration     Config (Config, separatorText, wrapping),     Wrapping (Wrap, NoWrap),+    Context (FullContext, Surrounding),      -- * pretty printing     pretty,+    prettyMultilines,     above,     below,   )@@ -37,56 +39,55 @@ import qualified Data.Algorithm.Diff as Diff import Data.Default (Default, def) import Data.Function ((&))-import Data.List (transpose)+import Data.List (take, transpose, zipWith) import Data.Maybe (fromMaybe, mapMaybe) import Data.String (IsString)-import qualified Data.Text as Text import Data.Text (Text)+import qualified Data.Text as 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-      }+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}@@ -96,31 +97,53 @@   = Wrap Int   | NoWrap +-- | Define how much context surrounding diffs you'd like to show.+data Context+  = FullContext+  | Surrounding Int Text+ -- | Printing a full diff of both values separated by some pipes.-pretty :: Show a => Config -> a -> a -> Text-pretty Config {separatorText, wrapping} x y =-  [ above wrapping x y,+pretty :: Config -> Text -> Text -> Text+pretty config x y =+  prettyMultilines config FullContext [x] [y]++-- | Printing a full diff of both values separated by some pipes.+prettyMultilines :: Config -> Context -> [Text] -> [Text] -> Text+prettyMultilines Config {separatorText, wrapping} context xs ys =+  [ zipWith (\x y -> above' wrapping x y) xs ys & extractContext context (False, [], []) & mconcat,     separator separatorText,-    below wrapping x y+    zipWith (\x y -> below' wrapping x y) xs ys & extractContext context (False, [], []) & mconcat   ]     & mconcat  -- | Printing The first value and the diff indicator above. -- --  @---  Diff.above Diff.NoWrap "1234" "_23"+--  Diff.above Diff.NoWrap Diff.FullContext "1234" "_23" --  @ -- --  @ --  ▼ ▼ -- "1234" --  @-above :: Show a => Wrapping -> a -> a -> Text+above :: Wrapping -> Text -> Text -> Text above wrapping x y =-  wrap wrapping [diffLine First down x y, Text.pack (show x)]-    & filterEmptyLines-    & Text.unlines+  let (_, res) = above' wrapping x y+   in res +above' :: Wrapping -> Text -> Text -> (Bool, Text)+above' wrapping x y =+  let diffs =+        Diff.getDiff+          (Text.unpack x)+          (Text.unpack y)+   in ( any (hasDiff First) diffs,+        withDiffLine First down diffs+          & wrap wrapping+          & filterEmptyLines+          & Text.unlines+      )+ -- | Printing The second value and the diff indicator below. -- --  @@@ -131,12 +154,24 @@ -- "_23" --  ▲ --  @-below :: Show a => Wrapping -> a -> a -> Text+below :: Wrapping -> Text -> Text -> Text below wrapping x y =-  wrap wrapping [Text.pack (show y), diffLine Second up x y]-    & filterEmptyLines-    & Text.unlines+  let (_, res) = below' wrapping x y+   in res +below' :: Wrapping -> Text -> Text -> (Bool, Text)+below' wrapping x y =+  let diffs =+        Diff.getDiff+          (Text.unpack x)+          (Text.unpack y)+   in ( any (hasDiff Second) diffs,+        withDiffLine Second up diffs+          & wrap wrapping+          & filterEmptyLines+          & Text.unlines+      )+ wrap :: Wrapping -> [Text] -> [Text] wrap wrapping text =   case wrapping of@@ -154,25 +189,77 @@  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+withDiffLine :: Position -> Char -> [Diff.Diff Char] -> [Text]+withDiffLine pos differ diffs =+  let (content, indicators) =+        diffs+          & mapMaybe (toDiffLine pos differ)+          & unzip+   in case pos of+        First -> [Text.pack indicators & Text.stripEnd, Text.pack content & Text.stripEnd]+        Second -> [Text.pack content & Text.stripEnd, Text.pack indicators & Text.stripEnd] -toDiffLine :: Position -> Char -> Diff.Diff a -> Maybe Char+toDiffLine :: Position -> Char -> Diff.Diff Char -> Maybe (Char, Char) toDiffLine pos c d =   case d of-    Diff.First _ -> case pos of-      First -> Just c+    Diff.First x -> case pos of+      First -> Just (x, c)       Second -> Nothing-    Diff.Second _ -> case pos of+    Diff.Second x -> case pos of       First -> Nothing-      Second -> Just c-    Diff.Both _ _ -> Just ' '+      Second -> Just (x, c)+    Diff.Both x _ -> Just (x, ' ')++extractContext :: Context -> (Bool, [Text], [Text]) -> [(Bool, Text)] -> [Text]+extractContext FullContext _ xs = map (\(_, a) -> a) xs+extractContext context@(Surrounding c sep) (hadDiff, acc, before) xs =+  case xs of+    [] ->+      if length before <= c+        then acc ++ before+        else acc ++ take c before ++ [sep, "\n"]+    (True, x) : rest ->+      extractContext+        context+        ( True,+          acc ++ splitSurrounding c sep hadDiff before ++ [x],+          []+        )+        rest+    (False, x) : rest ->+      extractContext+        context+        ( hadDiff,+          acc,+          before ++ [x]+        )+        rest++splitSurrounding :: Int -> Text -> Bool -> [Text] -> [Text]+splitSurrounding n sep hadDiff xs =+  if hadDiff+    then+      if length xs <= n * 2+        then xs+        else take n xs ++ [sep, "\n"] ++ takeRight n xs+    else+      if length xs <= n+        then xs+        else [sep, "\n"] ++ takeRight n xs++takeRight :: Int -> [a] -> [a]+takeRight i xs = reverse (take i (reverse xs))++hasDiff :: Position -> Diff.Diff Char -> Bool+hasDiff pos d =+  case d of+    Diff.First _ -> case pos of+      First -> True+      Second -> False+    Diff.Second x -> case pos of+      First -> False+      Second -> True+    Diff.Both x _ -> False  separator :: Maybe Text -> Text separator maybeComparison =
test/Main.hs view
@@ -22,134 +22,224 @@ 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)" $+    [ testGroup+        "pretty"+        [ testCase "Comparing two equal strings" $+            expectDiffToEqual+              ( Diff.pretty+                  def+                  "Hello"+                  "Hello"+              )+              [ "Hello",+                "╷",+                "│",+                "╵",+                "Hello"+              ],+          testCase "Removed characters" $+            expectDiffToEqual+              ( Diff.pretty+                  def+                  "Hello"+                  "Hel"+              )+              [ "   ▼▼",+                "Hello",+                "╷",+                "│",+                "╵",+                "Hel"+              ],+          testCase "Added characters" $+            expectDiffToEqual+              ( Diff.pretty+                  def+                  "Hel"+                  "Hello"+              )+              [ "Hel",+                "╷",+                "│",+                "╵",+                "Hello",+                "   ▲▲"+              ],+          testCase "Changed characters" $+            expectDiffToEqual+              ( Diff.pretty+                  def+                  "Axxx"+                  "Bxxx"+              )+              [ "▼",+                "Axxx",+                "╷",+                "│",+                "╵",+                "Bxxx",+                "▲"+              ],+          testCase "Mixed changes" $+            expectDiffToEqual+              ( Diff.pretty+                  def+                  "12345"+                  "1004"+              )+              [ " ▼▼ ▼",+                "12345",+                "╷",+                "│",+                "╵",+                "1004",+                " ▲▲"+              ],+          testCase "Multiline changes (on first and last line)" $+            expectDiffToEqual+              ( Diff.pretty+                  def {Diff.wrapping = Diff.Wrap 5}+                  "0900000000"+                  "9000000000"+              )+              [ "▼",+                "09000",+                "00000",+                "╷",+                "│",+                "╵",+                "90000",+                "00000",+                "    ▲"+              ],+          testCase "Multiline changes (inbetween)" $+            expectDiffToEqual+              ( Diff.pretty+                  def+                    { Diff.wrapping = Diff.Wrap 5+                    }+                  "0000090000"+                  "0090000000"+              )+              [ "00000",+                "▼",+                "90000",+                "╷",+                "│",+                "╵",+                "00900",+                "  ▲",+                "00000"+              ],+          testCase "With separator text" $+            expectDiffToEqual+              ( Diff.pretty+                  Diff.Config+                    { Diff.separatorText = Just "equals",+                      Diff.wrapping = Diff.Wrap 5+                    }+                  "0000090000"+                  "0090000000"+              )+              [ "00000",+                "▼",+                "90000",+                "╷",+                "│ equals",+                "╵",+                "00900",+                "  ▲",+                "00000"+              ]+        ],+      testGroup+        "prettyMultilines"+        [ testCase "Multiline content with full context" $+            expectDiffToEqual+              ( Diff.prettyMultilines+                  def+                  Diff.FullContext+                  ["a", "b", "c", "d", "e", "f"]+                  ["a", "b", "c", "D", "e", "f"]+              )+              [ "a",+                "b",+                "c",+                "▼",+                "d",+                "e",+                "f",+                "╷",+                "│",+                "╵",+                "a",+                "b",+                "c",+                "D",+                "▲",+                "e",+                "f"+              ]+        ],+      testCase "Multiline content with narrow context" $         expectDiffToEqual-          ( Diff.pretty+          ( Diff.prettyMultilines               def-                { Diff.wrapping = Diff.Wrap $ 5 + 1 -- + 1 because of "-                }-              "0000090000"-              "0090000000"+              (Diff.Surrounding 1 "...")+              ["a", "b", "c", "d", "e", "f"]+              ["a", "b", "c", "D", "e", "f"]           )-          [ "00000" & showTextPrefix,+          [ "...",+            "c",             "▼",-            "90000" & showTextPostfix,+            "d",+            "e",+            "...",             "╷",             "│",             "╵",-            "00900" & showTextPrefix,-            "  ▲" & forEscapedString,-            "00000" & showTextPostfix+            "...",+            "c",+            "D",+            "▲",+            "e",+            "..."           ],-      testCase "With separator text" $+      testCase "Multiline content with narrow context and multiple diffs" $         expectDiffToEqual-          ( Diff.pretty-              Diff.Config-                { Diff.separatorText = Just "equals",-                  Diff.wrapping = Diff.Wrap $ 5 + 1 -- + 1 because of "-                }-              "0000090000"-              "0090000000"+          ( Diff.prettyMultilines+              def {Diff.wrapping = Diff.Wrap 3}+              (Diff.Surrounding 1 "...")+              ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]+              ["A", "b", "c", "D", "e", "f", "g", "h", "i", "JJJJJJ"]           )-          [ "00000" & showTextPrefix,+          [ "▼",+            "a",+            "b",+            "c",             "▼",-            "90000" & showTextPostfix,+            "d",+            "e",+            "...",+            "i",+            "▼",+            "j",             "╷",-            "│ equals",+            "│",             "╵",-            "00900" & showTextPrefix,-            "  ▲" & forEscapedString,-            "00000" & showTextPostfix+            "A",+            "▲",+            "b",+            "c",+            "D",+            "▲",+            "e",+            "...",+            "i",+            "JJJ",+            "▲▲▲",+            "JJJ",+            "▲▲▲"           ]     ] @@ -163,11 +253,3 @@                 Text.IO.putStrLn expected                 throw e             )--forEscapedString x = " " <> x--showText = Text.pack . show--showTextPrefix x = "\"" <> x--showTextPostfix x = x <> "\""