{-# OPTIONS_HADDOCK not-home #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE PatternGuards #-}
module Hedgehog.Internal.Show (
    Name
  , Value(..)
  , ValueDiff(..)
  , LineDiff(..)

  , mkValue
  , showPretty

  , valueDiff
  , lineDiff
  , toLineDiff

  , renderValue
  , renderValueDiff
  , renderLineDiff

  , takeLeft
  , takeRight
  ) where

import           Data.Bifunctor (second)

import           Text.Show.Pretty (Value(..), Name, reify, valToStr, ppShow)


data ValueDiff =
    ValueCon Name [ValueDiff]
  | ValueRec Name [(Name, ValueDiff)]
  | ValueTuple [ValueDiff]
  | ValueList [ValueDiff]
  | ValueSame Value
  | ValueDiff Value Value
    deriving (ValueDiff -> ValueDiff -> Bool
(ValueDiff -> ValueDiff -> Bool)
-> (ValueDiff -> ValueDiff -> Bool) -> Eq ValueDiff
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ValueDiff -> ValueDiff -> Bool
$c/= :: ValueDiff -> ValueDiff -> Bool
== :: ValueDiff -> ValueDiff -> Bool
$c== :: ValueDiff -> ValueDiff -> Bool
Eq, Int -> ValueDiff -> ShowS
[ValueDiff] -> ShowS
ValueDiff -> String
(Int -> ValueDiff -> ShowS)
-> (ValueDiff -> String)
-> ([ValueDiff] -> ShowS)
-> Show ValueDiff
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ValueDiff] -> ShowS
$cshowList :: [ValueDiff] -> ShowS
show :: ValueDiff -> String
$cshow :: ValueDiff -> String
showsPrec :: Int -> ValueDiff -> ShowS
$cshowsPrec :: Int -> ValueDiff -> ShowS
Show)

data LineDiff =
    LineSame String
  | LineRemoved String
  | LineAdded String
    deriving (LineDiff -> LineDiff -> Bool
(LineDiff -> LineDiff -> Bool)
-> (LineDiff -> LineDiff -> Bool) -> Eq LineDiff
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: LineDiff -> LineDiff -> Bool
$c/= :: LineDiff -> LineDiff -> Bool
== :: LineDiff -> LineDiff -> Bool
$c== :: LineDiff -> LineDiff -> Bool
Eq, Int -> LineDiff -> ShowS
[LineDiff] -> ShowS
LineDiff -> String
(Int -> LineDiff -> ShowS)
-> (LineDiff -> String) -> ([LineDiff] -> ShowS) -> Show LineDiff
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [LineDiff] -> ShowS
$cshowList :: [LineDiff] -> ShowS
show :: LineDiff -> String
$cshow :: LineDiff -> String
showsPrec :: Int -> LineDiff -> ShowS
$cshowsPrec :: Int -> LineDiff -> ShowS
Show)

data DocDiff =
    DocSame Int String
  | DocRemoved Int String
  | DocAdded Int String
  | DocOpen Int String
  | DocItem Int String [DocDiff]
  | DocClose Int String
    deriving (DocDiff -> DocDiff -> Bool
(DocDiff -> DocDiff -> Bool)
-> (DocDiff -> DocDiff -> Bool) -> Eq DocDiff
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: DocDiff -> DocDiff -> Bool
$c/= :: DocDiff -> DocDiff -> Bool
== :: DocDiff -> DocDiff -> Bool
$c== :: DocDiff -> DocDiff -> Bool
Eq, Int -> DocDiff -> ShowS
[DocDiff] -> ShowS
DocDiff -> String
(Int -> DocDiff -> ShowS)
-> (DocDiff -> String) -> ([DocDiff] -> ShowS) -> Show DocDiff
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [DocDiff] -> ShowS
$cshowList :: [DocDiff] -> ShowS
show :: DocDiff -> String
$cshow :: DocDiff -> String
showsPrec :: Int -> DocDiff -> ShowS
$cshowsPrec :: Int -> DocDiff -> ShowS
Show)

renderValue :: Value -> String
renderValue :: Value -> String
renderValue =
  Value -> String
valToStr

renderValueDiff :: ValueDiff -> String
renderValueDiff :: ValueDiff -> String
renderValueDiff =
  [String] -> String
unlines ([String] -> String)
-> (ValueDiff -> [String]) -> ValueDiff -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  (LineDiff -> String) -> [LineDiff] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap LineDiff -> String
renderLineDiff ([LineDiff] -> [String])
-> (ValueDiff -> [LineDiff]) -> ValueDiff -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  ValueDiff -> [LineDiff]
toLineDiff

renderLineDiff :: LineDiff -> String
renderLineDiff :: LineDiff -> String
renderLineDiff = \case
  LineSame String
x ->
    String
"  " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
x
  LineRemoved String
x ->
    String
"- " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
x
  LineAdded String
x ->
    String
"+ " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
x

mkValue :: Show a => a -> Maybe Value
mkValue :: a -> Maybe Value
mkValue =
  a -> Maybe Value
forall a. Show a => a -> Maybe Value
reify

showPretty :: Show a => a -> String
showPretty :: a -> String
showPretty =
  a -> String
forall a. Show a => a -> String
ppShow

lineDiff :: Value -> Value -> [LineDiff]
lineDiff :: Value -> Value -> [LineDiff]
lineDiff Value
x Value
y =
  ValueDiff -> [LineDiff]
toLineDiff (ValueDiff -> [LineDiff]) -> ValueDiff -> [LineDiff]
forall a b. (a -> b) -> a -> b
$ Value -> Value -> ValueDiff
valueDiff Value
x Value
y

toLineDiff :: ValueDiff -> [LineDiff]
toLineDiff :: ValueDiff -> [LineDiff]
toLineDiff =
  (DocDiff -> [LineDiff]) -> [DocDiff] -> [LineDiff]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Int -> String -> DocDiff -> [LineDiff]
mkLineDiff Int
0 String
"") ([DocDiff] -> [LineDiff])
-> (ValueDiff -> [DocDiff]) -> ValueDiff -> [LineDiff]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  [DocDiff] -> [DocDiff]
collapseOpen ([DocDiff] -> [DocDiff])
-> (ValueDiff -> [DocDiff]) -> ValueDiff -> [DocDiff]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  [DocDiff] -> [DocDiff]
dropLeadingSep ([DocDiff] -> [DocDiff])
-> (ValueDiff -> [DocDiff]) -> ValueDiff -> [DocDiff]
forall b c a. (b -> c) -> (a -> b) -> a -> c
.
  Int -> ValueDiff -> [DocDiff]
mkDocDiff Int
0

valueDiff :: Value -> Value -> ValueDiff
valueDiff :: Value -> Value -> ValueDiff
valueDiff Value
x Value
y =
  if Value
x Value -> Value -> Bool
forall a. Eq a => a -> a -> Bool
== Value
y then
    Value -> ValueDiff
ValueSame Value
x
  else
    case (Value
x, Value
y) of
      (Con String
nx [Value]
xs, Con String
ny [Value]
ys)
        | String
nx String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
ny
        , [Value] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Value]
xs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [Value] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Value]
ys
        ->
          String -> [ValueDiff] -> ValueDiff
ValueCon String
nx ((Value -> Value -> ValueDiff) -> [Value] -> [Value] -> [ValueDiff]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Value -> Value -> ValueDiff
valueDiff [Value]
xs [Value]
ys)

      (Rec String
nx [(String, Value)]
nxs, Rec String
ny [(String, Value)]
nys)
        | String
nx String -> String -> Bool
forall a. Eq a => a -> a -> Bool
== String
ny
        , ((String, Value) -> String) -> [(String, Value)] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String, Value) -> String
forall a b. (a, b) -> a
fst [(String, Value)]
nxs [String] -> [String] -> Bool
forall a. Eq a => a -> a -> Bool
== ((String, Value) -> String) -> [(String, Value)] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String, Value) -> String
forall a b. (a, b) -> a
fst [(String, Value)]
nys
        , [String]
ns <- ((String, Value) -> String) -> [(String, Value)] -> [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String, Value) -> String
forall a b. (a, b) -> a
fst [(String, Value)]
nxs
        , [Value]
xs <- ((String, Value) -> Value) -> [(String, Value)] -> [Value]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String, Value) -> Value
forall a b. (a, b) -> b
snd [(String, Value)]
nxs
        , [Value]
ys <- ((String, Value) -> Value) -> [(String, Value)] -> [Value]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (String, Value) -> Value
forall a b. (a, b) -> b
snd [(String, Value)]
nys
        ->
          String -> [(String, ValueDiff)] -> ValueDiff
ValueRec String
nx ([String] -> [ValueDiff] -> [(String, ValueDiff)]
forall a b. [a] -> [b] -> [(a, b)]
zip [String]
ns ((Value -> Value -> ValueDiff) -> [Value] -> [Value] -> [ValueDiff]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Value -> Value -> ValueDiff
valueDiff [Value]
xs [Value]
ys))

      (Tuple [Value]
xs, Tuple [Value]
ys)
        | [Value] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Value]
xs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [Value] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Value]
ys
        ->
          [ValueDiff] -> ValueDiff
ValueTuple ((Value -> Value -> ValueDiff) -> [Value] -> [Value] -> [ValueDiff]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Value -> Value -> ValueDiff
valueDiff [Value]
xs [Value]
ys)

      (List [Value]
xs, List [Value]
ys)
        | [Value] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Value]
xs Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== [Value] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Value]
ys
        ->
          [ValueDiff] -> ValueDiff
ValueList ((Value -> Value -> ValueDiff) -> [Value] -> [Value] -> [ValueDiff]
forall a b c. (a -> b -> c) -> [a] -> [b] -> [c]
zipWith Value -> Value -> ValueDiff
valueDiff [Value]
xs [Value]
ys)

      (Value, Value)
_ ->
        Value -> Value -> ValueDiff
ValueDiff Value
x Value
y

takeLeft :: ValueDiff -> Value
takeLeft :: ValueDiff -> Value
takeLeft = \case
  ValueCon String
n [ValueDiff]
xs ->
    String -> [Value] -> Value
Con String
n ((ValueDiff -> Value) -> [ValueDiff] -> [Value]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ValueDiff -> Value
takeLeft [ValueDiff]
xs)
  ValueRec String
n [(String, ValueDiff)]
nxs ->
    String -> [(String, Value)] -> Value
Rec String
n (((String, ValueDiff) -> (String, Value))
-> [(String, ValueDiff)] -> [(String, Value)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ValueDiff -> Value) -> (String, ValueDiff) -> (String, Value)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ValueDiff -> Value
takeLeft) [(String, ValueDiff)]
nxs)
  ValueTuple [ValueDiff]
xs ->
    [Value] -> Value
Tuple ((ValueDiff -> Value) -> [ValueDiff] -> [Value]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ValueDiff -> Value
takeLeft [ValueDiff]
xs)
  ValueList [ValueDiff]
xs ->
    [Value] -> Value
List ((ValueDiff -> Value) -> [ValueDiff] -> [Value]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ValueDiff -> Value
takeLeft [ValueDiff]
xs)
  ValueSame Value
x ->
    Value
x
  ValueDiff Value
x Value
_ ->
    Value
x

takeRight :: ValueDiff -> Value
takeRight :: ValueDiff -> Value
takeRight = \case
  ValueCon String
n [ValueDiff]
xs ->
    String -> [Value] -> Value
Con String
n ((ValueDiff -> Value) -> [ValueDiff] -> [Value]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ValueDiff -> Value
takeRight [ValueDiff]
xs)
  ValueRec String
n [(String, ValueDiff)]
nxs ->
    String -> [(String, Value)] -> Value
Rec String
n (((String, ValueDiff) -> (String, Value))
-> [(String, ValueDiff)] -> [(String, Value)]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((ValueDiff -> Value) -> (String, ValueDiff) -> (String, Value)
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second ValueDiff -> Value
takeRight) [(String, ValueDiff)]
nxs)
  ValueTuple [ValueDiff]
xs ->
    [Value] -> Value
Tuple ((ValueDiff -> Value) -> [ValueDiff] -> [Value]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ValueDiff -> Value
takeRight [ValueDiff]
xs)
  ValueList [ValueDiff]
xs ->
    [Value] -> Value
List ((ValueDiff -> Value) -> [ValueDiff] -> [Value]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ValueDiff -> Value
takeRight [ValueDiff]
xs)
  ValueSame Value
x ->
    Value
x
  ValueDiff Value
_ Value
x ->
    Value
x

mkLineDiff :: Int -> String -> DocDiff -> [LineDiff]
mkLineDiff :: Int -> String -> DocDiff -> [LineDiff]
mkLineDiff Int
indent0 String
prefix0 DocDiff
diff =
  let
    mkLinePrefix :: Int -> String
mkLinePrefix Int
indent =
      Int -> String
spaces Int
indent0 String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
prefix0 String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
spaces Int
indent

    mkLineIndent :: Int -> Int
mkLineIndent Int
indent =
      Int
indent0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
prefix0 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
indent
  in
    case DocDiff
diff of
      DocSame Int
indent String
x ->
        [String -> LineDiff
LineSame (String -> LineDiff) -> String -> LineDiff
forall a b. (a -> b) -> a -> b
$ Int -> String
mkLinePrefix Int
indent String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
x]

      DocRemoved Int
indent String
x ->
        [String -> LineDiff
LineRemoved (String -> LineDiff) -> String -> LineDiff
forall a b. (a -> b) -> a -> b
$ Int -> String
mkLinePrefix Int
indent String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
x]

      DocAdded Int
indent String
x ->
        [String -> LineDiff
LineAdded (String -> LineDiff) -> String -> LineDiff
forall a b. (a -> b) -> a -> b
$ Int -> String
mkLinePrefix Int
indent String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
x]

      DocOpen Int
indent String
x ->
        [String -> LineDiff
LineSame (String -> LineDiff) -> String -> LineDiff
forall a b. (a -> b) -> a -> b
$ Int -> String
mkLinePrefix Int
indent String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
x]

      DocItem Int
_ String
_ [] ->
        []

      DocItem Int
indent String
prefix (x :: DocDiff
x@DocRemoved{} : y :: DocDiff
y@DocAdded{} : [DocDiff]
xs) ->
        Int -> String -> DocDiff -> [LineDiff]
mkLineDiff (Int -> Int
mkLineIndent Int
indent) String
prefix DocDiff
x [LineDiff] -> [LineDiff] -> [LineDiff]
forall a. [a] -> [a] -> [a]
++
        Int -> String -> DocDiff -> [LineDiff]
mkLineDiff (Int -> Int
mkLineIndent Int
indent) String
prefix DocDiff
y [LineDiff] -> [LineDiff] -> [LineDiff]
forall a. [a] -> [a] -> [a]
++
        (DocDiff -> [LineDiff]) -> [DocDiff] -> [LineDiff]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Int -> String -> DocDiff -> [LineDiff]
mkLineDiff (Int -> Int
mkLineIndent (Int
indent Int -> Int -> Int
forall a. Num a => a -> a -> a
+ String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
prefix)) String
"") [DocDiff]
xs

      DocItem Int
indent String
prefix (DocDiff
x : [DocDiff]
xs) ->
        Int -> String -> DocDiff -> [LineDiff]
mkLineDiff (Int -> Int
mkLineIndent Int
indent) String
prefix DocDiff
x [LineDiff] -> [LineDiff] -> [LineDiff]
forall a. [a] -> [a] -> [a]
++
        (DocDiff -> [LineDiff]) -> [DocDiff] -> [LineDiff]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Int -> String -> DocDiff -> [LineDiff]
mkLineDiff (Int -> Int
mkLineIndent (Int
indent Int -> Int -> Int
forall a. Num a => a -> a -> a
+ String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
prefix)) String
"") [DocDiff]
xs

      DocClose Int
indent String
x ->
        [String -> LineDiff
LineSame (String -> LineDiff) -> String -> LineDiff
forall a b. (a -> b) -> a -> b
$ Int -> String
spaces (Int -> Int
mkLineIndent Int
indent) String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
x]

spaces :: Int -> String
spaces :: Int -> String
spaces Int
indent =
  Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
indent Char
' '

collapseOpen :: [DocDiff] -> [DocDiff]
collapseOpen :: [DocDiff] -> [DocDiff]
collapseOpen = \case
  DocSame Int
indent String
line : DocOpen Int
_ String
bra : [DocDiff]
xs ->
    Int -> String -> DocDiff
DocSame Int
indent (String
line String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
bra) DocDiff -> [DocDiff] -> [DocDiff]
forall a. a -> [a] -> [a]
: [DocDiff] -> [DocDiff]
collapseOpen [DocDiff]
xs
  DocItem Int
indent String
prefix [DocDiff]
xs : [DocDiff]
ys ->
    Int -> String -> [DocDiff] -> DocDiff
DocItem Int
indent String
prefix ([DocDiff] -> [DocDiff]
collapseOpen [DocDiff]
xs) DocDiff -> [DocDiff] -> [DocDiff]
forall a. a -> [a] -> [a]
: [DocDiff] -> [DocDiff]
collapseOpen [DocDiff]
ys
  DocDiff
x : [DocDiff]
xs ->
    DocDiff
x DocDiff -> [DocDiff] -> [DocDiff]
forall a. a -> [a] -> [a]
: [DocDiff] -> [DocDiff]
collapseOpen [DocDiff]
xs
  [] ->
    []

dropLeadingSep :: [DocDiff] -> [DocDiff]
dropLeadingSep :: [DocDiff] -> [DocDiff]
dropLeadingSep = \case
  DocOpen Int
oindent String
bra : DocItem Int
indent String
prefix [DocDiff]
xs : [DocDiff]
ys ->
    Int -> String -> DocDiff
DocOpen Int
oindent String
bra DocDiff -> [DocDiff] -> [DocDiff]
forall a. a -> [a] -> [a]
: Int -> String -> [DocDiff] -> DocDiff
DocItem (Int
indent Int -> Int -> Int
forall a. Num a => a -> a -> a
+ String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
prefix) String
"" ([DocDiff] -> [DocDiff]
dropLeadingSep [DocDiff]
xs) DocDiff -> [DocDiff] -> [DocDiff]
forall a. a -> [a] -> [a]
: [DocDiff] -> [DocDiff]
dropLeadingSep [DocDiff]
ys
  DocItem Int
indent String
prefix [DocDiff]
xs : [DocDiff]
ys ->
    Int -> String -> [DocDiff] -> DocDiff
DocItem Int
indent String
prefix ([DocDiff] -> [DocDiff]
dropLeadingSep [DocDiff]
xs) DocDiff -> [DocDiff] -> [DocDiff]
forall a. a -> [a] -> [a]
: [DocDiff] -> [DocDiff]
dropLeadingSep [DocDiff]
ys
  DocDiff
x : [DocDiff]
xs ->
    DocDiff
x DocDiff -> [DocDiff] -> [DocDiff]
forall a. a -> [a] -> [a]
: [DocDiff] -> [DocDiff]
dropLeadingSep [DocDiff]
xs
  [] ->
    []

mkDocDiff :: Int -> ValueDiff -> [DocDiff]
mkDocDiff :: Int -> ValueDiff -> [DocDiff]
mkDocDiff Int
indent = \case
  ValueSame Value
x ->
    Int -> String -> [DocDiff]
same Int
indent (Value -> String
renderValue Value
x)

  ValueDiff
diff
    | Value
x <- ValueDiff -> Value
takeLeft ValueDiff
diff
    , Value
y <- ValueDiff -> Value
takeRight ValueDiff
diff
    , Value -> Bool
oneLiner Value
x
    , Value -> Bool
oneLiner Value
y
    ->
      Int -> String -> [DocDiff]
removed Int
indent (Value -> String
renderValue Value
x) [DocDiff] -> [DocDiff] -> [DocDiff]
forall a. [a] -> [a] -> [a]
++
      Int -> String -> [DocDiff]
added Int
indent (Value -> String
renderValue Value
y)

  ValueCon String
n [ValueDiff]
xs ->
    Int -> String -> [DocDiff]
same Int
indent String
n [DocDiff] -> [DocDiff] -> [DocDiff]
forall a. [a] -> [a] -> [a]
++
    (ValueDiff -> [DocDiff]) -> [ValueDiff] -> [DocDiff]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (Int -> ValueDiff -> [DocDiff]
mkDocDiff (Int
indent Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2)) [ValueDiff]
xs

  ValueRec String
n [(String, ValueDiff)]
nxs ->
    Int -> String -> [DocDiff]
same Int
indent String
n [DocDiff] -> [DocDiff] -> [DocDiff]
forall a. [a] -> [a] -> [a]
++
    [Int -> String -> DocDiff
DocOpen Int
indent String
"{"] [DocDiff] -> [DocDiff] -> [DocDiff]
forall a. [a] -> [a] -> [a]
++
    ((String, ValueDiff) -> DocDiff)
-> [(String, ValueDiff)] -> [DocDiff]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(String
name, ValueDiff
x) -> Int -> String -> [DocDiff] -> DocDiff
DocItem (Int
indent Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) String
", " (Int -> String -> [DocDiff]
same Int
0 (String
name String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
" =") [DocDiff] -> [DocDiff] -> [DocDiff]
forall a. [a] -> [a] -> [a]
++ Int -> ValueDiff -> [DocDiff]
mkDocDiff Int
2 ValueDiff
x)) [(String, ValueDiff)]
nxs [DocDiff] -> [DocDiff] -> [DocDiff]
forall a. [a] -> [a] -> [a]
++
    [Int -> String -> DocDiff
DocClose (Int
indent Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2) String
"}"]

  ValueTuple [ValueDiff]
xs ->
    [Int -> String -> DocDiff
DocOpen Int
indent String
"("] [DocDiff] -> [DocDiff] -> [DocDiff]
forall a. [a] -> [a] -> [a]
++
    (ValueDiff -> DocDiff) -> [ValueDiff] -> [DocDiff]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> String -> [DocDiff] -> DocDiff
DocItem Int
indent String
", " ([DocDiff] -> DocDiff)
-> (ValueDiff -> [DocDiff]) -> ValueDiff -> DocDiff
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ValueDiff -> [DocDiff]
mkDocDiff Int
0) [ValueDiff]
xs [DocDiff] -> [DocDiff] -> [DocDiff]
forall a. [a] -> [a] -> [a]
++
    [Int -> String -> DocDiff
DocClose Int
indent String
")"]

  ValueList [ValueDiff]
xs ->
    [Int -> String -> DocDiff
DocOpen Int
indent String
"["] [DocDiff] -> [DocDiff] -> [DocDiff]
forall a. [a] -> [a] -> [a]
++
    (ValueDiff -> DocDiff) -> [ValueDiff] -> [DocDiff]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> String -> [DocDiff] -> DocDiff
DocItem Int
indent String
", " ([DocDiff] -> DocDiff)
-> (ValueDiff -> [DocDiff]) -> ValueDiff -> DocDiff
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ValueDiff -> [DocDiff]
mkDocDiff Int
0) [ValueDiff]
xs [DocDiff] -> [DocDiff] -> [DocDiff]
forall a. [a] -> [a] -> [a]
++
    [Int -> String -> DocDiff
DocClose Int
indent String
"]"]

  ValueDiff Value
x Value
y ->
    Int -> String -> [DocDiff]
removed Int
indent (Value -> String
renderValue Value
x) [DocDiff] -> [DocDiff] -> [DocDiff]
forall a. [a] -> [a] -> [a]
++
    Int -> String -> [DocDiff]
added Int
indent (Value -> String
renderValue Value
y)

oneLiner :: Value -> Bool
oneLiner :: Value -> Bool
oneLiner Value
x =
  case String -> [String]
lines (Value -> String
renderValue Value
x) of
    String
_ : String
_ : [String]
_ ->
      Bool
False
    [String]
_ ->
      Bool
True

same :: Int -> String -> [DocDiff]
same :: Int -> String -> [DocDiff]
same Int
indent =
  (String -> DocDiff) -> [String] -> [DocDiff]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> String -> DocDiff
DocSame Int
indent) ([String] -> [DocDiff])
-> (String -> [String]) -> String -> [DocDiff]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines

removed :: Int -> String -> [DocDiff]
removed :: Int -> String -> [DocDiff]
removed Int
indent =
  (String -> DocDiff) -> [String] -> [DocDiff]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> String -> DocDiff
DocRemoved Int
indent) ([String] -> [DocDiff])
-> (String -> [String]) -> String -> [DocDiff]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines

added :: Int -> String -> [DocDiff]
added :: Int -> String -> [DocDiff]
added Int
indent =
  (String -> DocDiff) -> [String] -> [DocDiff]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (Int -> String -> DocDiff
DocAdded Int
indent) ([String] -> [DocDiff])
-> (String -> [String]) -> String -> [DocDiff]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> [String]
lines