aeson-pretty
aeson-pretty copied to clipboard
Add an option to color the output
Implementation
A function to convert a JSON Value to a list of color commands [SGR] from the ansi-terminal package has been added to both Config and PState.
defConfig still has the same behavior of no color (using noColors).
encodePretty still has the default behavior of no color (implemented as encodePretty' defConfig)
encodePretty' colorConfig colors the output by inserting color codes which are interpreted by the terminal.
Example
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson.Encode.Pretty
import Data.Aeson (Value(..), ToJSON(..), eitherDecode)
import qualified Data.Aeson.Encode as Aeson
import qualified Data.ByteString.Lazy as BS
import qualified Data.ByteString.Lazy.Char8 as BSC
someJSON :: BS.ByteString
someJSON = "[null,1337,true,\"hi\nthere\",{\"prop\":\"value\",\"p2\":false,\"p3\":3,\"p4\":\"hi\",\"p5\":null}]"
main :: IO ()
main = do
BSC.putStrLn $ either BSC.pack encodePretty (eitherDecode someJSON :: Either String Value)
BSC.putStrLn $ either BSC.pack (encodePretty' colorConfig) (eitherDecode someJSON :: Either String Value)
Output to terminal

Piped into Vim

I like this feature, thanks for the pull request. But the code needs some more work.
-
I prefer
confColors :: Value -> [SGR]to theValue -> Stringversion, since it is more specifically typed. This also ensures, that no invalid codes are created. -
There are empty objects passed to the
confColorsfunction, instead of the object actually colored. This means I can not change colors depending on the object's content. E.g. change background color of arrays with more than three elements. The type ofconfColorssuggests this is possible. -
Arrays use the colors forobjects (the "punctuation" value) -
Arguably, some
Resets should always be inserted after the elements of an array or object. If you have a color configuration like thiscolors :: (Value -> String) colors (Array _) = setSGRCode [SetColor Foreground Vivid White] colors (String _) = setSGRCode [Reset, SetColor Background Vivid Red] ...
the background of the String will "leak out" of a surrounding array. I am unsure if a Reset should also be inserted at the very end, to not leak into any following data.
- There is some duplication:
toColor pstColor (object [])is all over the place, the "punctuation" (why that name?) should be moved intofromCompound. PerhapspstColorshould have typeValue -> Builderotherwise you always calltoColor pstColor.
- Agreed,
Value -> [SGR]is better because it prevents invalid color codes. - I feel like color should be independent of content, so something like
JSONType -> [SGR]would be even better. However, I don't think it's possible to pass the tag without the values, so I believeJSONTypewould need to be a new data type.
We could go a step further and define colors for every piece of output (like some kind of syntax tree data type), including different colors for each punctuation character (and whitespace too): {}[],:". That might be overkill, though.
Arrays probably should not share colors withObjects. The only reason I did that was so that all punctuation characters had the same color.- You're right, a
Resetneeds to be inserted before and after every element to prevent color bleed. - Yes, the multiple
toColor pstColor (object [])are annoying. That andtoColorcould probably be cleaned up. And yes, the punctuation should be moved intofromCompound.
I like Value -> [SRG] because it offers a superset of the JSONType -> [SRG] functionality, while using existing types. You are right, that color-by-content is an unlikely case, but most people will probably use the default colors anyway and won't bother with defining their own. The experts will have to deal with the additional options. And pattern matching the Value constructors with underscores for the content (as you did in defColors) is very declarative, in my opinion. The definition of defColors could even be copied into the Haddock, as an example.
Regarding the "step further", yes I think that goes too far. :-)