Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an option to color the output #8

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

chrismwendt
Copy link
Contributor

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

image

Piped into Vim

image

@chrismwendt chrismwendt changed the title Feature/color Add an option to color the output Sep 13, 2014
@informatikr
Copy link
Owner

I like this feature, thanks for the pull request. But the code needs some more work.

  • I prefer confColors :: Value -> [SGR] to the Value -> String version, since it is more specifically typed. This also ensures, that no invalid codes are created.

  • There are empty objects passed to the confColors function, 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 of confColors suggests this is possible.

  • Arrays use the colors for objects (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 this

    colors :: (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 into fromCompound. Perhaps pstColor should have type Value -> Builder otherwise you always call toColor pstColor.

@chrismwendt
Copy link
Contributor Author

  • 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 believe JSONType would 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 with Objects. The only reason I did that was so that all punctuation characters had the same color.
  • You're right, a Reset needs to be inserted before and after every element to prevent color bleed.
  • Yes, the multiple toColor pstColor (object []) are annoying. That and toColor could probably be cleaned up. And yes, the punctuation should be moved into fromCompound.

@informatikr
Copy link
Owner

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. :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants