2017-03-31 23:08:39 +03:00
|
|
|
{-# LANGUAGE GADTs #-}
|
2017-03-31 22:55:57 +03:00
|
|
|
module Renderer
|
2017-03-31 23:50:13 +03:00
|
|
|
( DiffRenderer(..)
|
|
|
|
, runDiffRenderer
|
2017-03-31 23:54:55 +03:00
|
|
|
, runDiffRenderer'
|
2017-03-31 23:50:13 +03:00
|
|
|
, Renderer
|
2017-03-31 22:55:57 +03:00
|
|
|
, Output(..)
|
|
|
|
, concatOutputs
|
|
|
|
, Format(..)
|
2017-04-03 22:31:46 +03:00
|
|
|
, Summaries(..)
|
2017-03-31 22:55:57 +03:00
|
|
|
) where
|
2016-01-14 21:18:40 +03:00
|
|
|
|
2017-03-31 23:08:39 +03:00
|
|
|
import Data.Aeson (ToJSON, Value, encode)
|
2016-09-09 21:46:50 +03:00
|
|
|
import Data.Functor.Both
|
2016-08-24 21:30:29 +03:00
|
|
|
import Data.Map as Map hiding (null)
|
2017-03-08 01:08:32 +03:00
|
|
|
import Data.Text.Encoding (encodeUtf8)
|
|
|
|
import qualified Data.ByteString as B
|
2017-03-01 01:55:57 +03:00
|
|
|
import Data.Functor.Listable
|
2017-03-31 23:08:39 +03:00
|
|
|
import Data.Record
|
2017-04-01 06:02:41 +03:00
|
|
|
import Diff
|
2017-03-31 23:08:39 +03:00
|
|
|
import Info
|
2017-03-09 01:45:47 +03:00
|
|
|
import Prologue
|
2017-03-31 23:49:29 +03:00
|
|
|
import Renderer.JSON as R
|
|
|
|
import Renderer.Patch as R
|
|
|
|
import Renderer.SExpression as R
|
|
|
|
import Renderer.Split as R
|
|
|
|
import Renderer.Summary as R
|
|
|
|
import Renderer.TOC as R
|
2016-09-09 21:46:50 +03:00
|
|
|
import Source (SourceBlob)
|
|
|
|
import Syntax
|
2016-01-14 21:18:40 +03:00
|
|
|
|
2017-03-31 23:08:39 +03:00
|
|
|
data DiffRenderer fields output where
|
|
|
|
SplitRenderer :: (HasField fields Category, HasField fields Range) => DiffRenderer fields Text
|
|
|
|
PatchRenderer :: HasField fields Range => DiffRenderer fields Text
|
|
|
|
JSONDiffRenderer :: (ToJSON (Record fields), HasField fields Category, HasField fields Range) => DiffRenderer fields (Map Text Value)
|
2017-04-03 22:37:20 +03:00
|
|
|
SummaryRenderer :: HasDefaultFields fields => DiffRenderer fields Summaries
|
2017-03-31 23:14:44 +03:00
|
|
|
SExpressionDiffRenderer :: (HasField fields Category, HasField fields SourceSpan) => SExpressionFormat -> DiffRenderer fields ByteString
|
2017-04-03 22:37:20 +03:00
|
|
|
ToCRenderer :: HasDefaultFields fields => DiffRenderer fields Summaries
|
2017-03-31 23:08:39 +03:00
|
|
|
|
2017-04-01 00:03:17 +03:00
|
|
|
runDiffRenderer :: DiffRenderer fields output -> Both SourceBlob -> Diff (Syntax Text) (Record fields) -> Output
|
2017-04-03 19:22:11 +03:00
|
|
|
runDiffRenderer renderer = case renderer of
|
|
|
|
SplitRenderer -> (SplitOutput .) . R.split
|
|
|
|
PatchRenderer -> (PatchOutput .) . R.patch
|
|
|
|
JSONDiffRenderer -> (JSONOutput .) . R.json
|
|
|
|
SummaryRenderer -> (SummaryOutput .) . R.summary
|
|
|
|
SExpressionDiffRenderer format -> (SExpressionOutput .) . R.sExpression format
|
|
|
|
ToCRenderer -> (TOCOutput .) . R.toc
|
2017-03-31 23:49:29 +03:00
|
|
|
|
2017-04-01 00:03:17 +03:00
|
|
|
runDiffRenderer' :: DiffRenderer fields output -> Both SourceBlob -> Diff (Syntax Text) (Record fields) -> output
|
2017-04-01 06:02:56 +03:00
|
|
|
runDiffRenderer' renderer = case renderer of
|
|
|
|
SplitRenderer -> R.split
|
|
|
|
PatchRenderer -> R.patch
|
|
|
|
JSONDiffRenderer -> R.json
|
2017-04-03 22:37:20 +03:00
|
|
|
SummaryRenderer -> (Summaries .) . R.summary
|
2017-04-01 06:02:56 +03:00
|
|
|
SExpressionDiffRenderer format -> R.sExpression format
|
2017-04-03 22:37:20 +03:00
|
|
|
ToCRenderer -> (Summaries .) . R.toc
|
2017-03-31 23:54:55 +03:00
|
|
|
|
2016-07-29 19:24:12 +03:00
|
|
|
-- | A function that will render a diff, given the two source blobs.
|
2016-09-09 21:46:50 +03:00
|
|
|
type Renderer annotation = Both SourceBlob -> Diff (Syntax Text) annotation -> Output
|
2016-04-01 22:34:52 +03:00
|
|
|
|
2016-08-22 16:38:18 +03:00
|
|
|
-- | The available types of diff rendering.
|
2017-03-11 01:12:23 +03:00
|
|
|
data Format = Split | Patch | JSON | Summary | SExpression | TOC | Index | ParseTree
|
2016-08-22 16:38:18 +03:00
|
|
|
deriving (Show)
|
|
|
|
|
2017-03-08 01:08:32 +03:00
|
|
|
data Output = SplitOutput Text | PatchOutput Text | JSONOutput (Map Text Value) | SummaryOutput (Map Text (Map Text [Value])) | SExpressionOutput ByteString | TOCOutput (Map Text (Map Text [Value]))
|
2016-08-22 16:27:13 +03:00
|
|
|
deriving (Show)
|
2016-08-22 04:51:48 +03:00
|
|
|
|
2017-04-03 22:31:46 +03:00
|
|
|
newtype Summaries = Summaries { unSummaries :: Map Text (Map Text [Value]) }
|
|
|
|
deriving Show
|
|
|
|
|
|
|
|
instance Monoid Summaries where
|
|
|
|
mempty = Summaries mempty
|
|
|
|
mappend = (Summaries .) . (Map.unionWith (Map.unionWith (<>)) `on` unSummaries)
|
|
|
|
|
2016-08-24 21:16:01 +03:00
|
|
|
-- Concatenates a list of 'Output' depending on the output type.
|
|
|
|
-- For JSON, each file output is merged since they're uniquely keyed by filename.
|
|
|
|
-- For Summaries, each file output is merged into one 'Object' consisting of lists of
|
|
|
|
-- changes and errors.
|
|
|
|
-- Split and Patch output is appended together with newlines.
|
2017-03-08 01:08:32 +03:00
|
|
|
concatOutputs :: [Output] -> ByteString
|
2017-03-09 01:45:47 +03:00
|
|
|
concatOutputs list | isJSON list = toS . encode $ concatJSON list
|
2016-08-24 21:07:00 +03:00
|
|
|
where
|
|
|
|
concatJSON :: [Output] -> Map Text Value
|
|
|
|
concatJSON (JSONOutput hash : rest) = Map.union hash (concatJSON rest)
|
|
|
|
concatJSON _ = mempty
|
2017-03-09 01:45:47 +03:00
|
|
|
concatOutputs list | isSummary list = toS . encode $ concatSummaries list
|
2016-08-24 21:07:00 +03:00
|
|
|
where
|
2016-10-06 20:12:40 +03:00
|
|
|
concatSummaries :: [Output] -> Map Text (Map Text [Value])
|
2017-04-03 22:37:20 +03:00
|
|
|
concatSummaries = unSummaries . foldMap toSummaries
|
2017-03-08 01:08:32 +03:00
|
|
|
concatOutputs list | isByteString list = B.intercalate "\n" (toByteString <$> list)
|
|
|
|
concatOutputs list | isText list = B.intercalate "\n" (encodeUtf8 . toText <$> list)
|
2016-08-22 04:51:48 +03:00
|
|
|
concatOutputs _ = mempty
|
|
|
|
|
|
|
|
isJSON :: [Output] -> Bool
|
|
|
|
isJSON (JSONOutput _ : _) = True
|
|
|
|
isJSON _ = False
|
|
|
|
|
|
|
|
isSummary :: [Output] -> Bool
|
|
|
|
isSummary (SummaryOutput _ : _) = True
|
2017-01-24 01:31:01 +03:00
|
|
|
isSummary (TOCOutput _ : _) = True
|
2016-08-22 04:51:48 +03:00
|
|
|
isSummary _ = False
|
|
|
|
|
|
|
|
isText :: [Output] -> Bool
|
|
|
|
isText (SplitOutput _ : _) = True
|
|
|
|
isText (PatchOutput _ : _) = True
|
|
|
|
isText _ = False
|
|
|
|
|
2016-08-10 19:17:23 +03:00
|
|
|
toText :: Output -> Text
|
|
|
|
toText (SplitOutput text) = text
|
|
|
|
toText (PatchOutput text) = text
|
2016-08-17 05:03:48 +03:00
|
|
|
toText _ = mempty
|
2017-03-01 01:55:57 +03:00
|
|
|
|
2017-04-03 22:37:20 +03:00
|
|
|
toSummaries :: Output -> Summaries
|
|
|
|
toSummaries (SummaryOutput s) = Summaries s
|
|
|
|
toSummaries (TOCOutput s) = Summaries s
|
|
|
|
toSummaries _ = mempty
|
|
|
|
|
2017-03-08 01:08:32 +03:00
|
|
|
isByteString :: [Output] -> Bool
|
|
|
|
isByteString (SExpressionOutput _ : _) = True
|
|
|
|
isByteString _ = False
|
|
|
|
|
|
|
|
toByteString :: Output -> ByteString
|
|
|
|
toByteString (SExpressionOutput text) = text
|
|
|
|
toByteString _ = B.empty
|
|
|
|
|
|
|
|
|
2017-03-01 01:55:57 +03:00
|
|
|
instance Listable Format where
|
|
|
|
tiers = cons0 Split
|
|
|
|
\/ cons0 Patch
|
|
|
|
\/ cons0 JSON
|
|
|
|
\/ cons0 Summary
|
|
|
|
\/ cons0 SExpression
|
|
|
|
\/ cons0 TOC
|