@@ -0,0 +1,379 @@
1+{-# OPTIONS_GHC -Wall #-}
2+{-# LANGUAGE OverloadedStrings #-}
6+ , P.cat, P.empty, P.fillSep, P.hang, P.hcat, P.hsep, P.indent, P.sep, P.vcat
7+ , P.black, P.blue, P.green, P.magenta, P.dullyellow, P.red, P.dullred
9+ , fromString, fromText, fromName
10+ , toAnsi, toString, toLine
13+ , stack, reflow, commaSep
14+ , toSimpleNote, toSimpleHint, toFancyHint
15+ , link, fancyLink, reflowLink, makeLink
16+ , args, moreArgs, ordinalize
22+import Prelude hiding (cycle)
23+import qualified Data.List as List
24+import Data.Monoid ((<>))
25+import qualified Data.Text as Text
26+import qualified Data.Text.Lazy as TL
27+import qualified Data.Text.Lazy.Builder as TB
28+import qualified Elm.Name as N
29+import qualified System.Console.ANSI.Types as Ansi
30+import System.IO (Handle)
31+import qualified Text.PrettyPrint.ANSI.Leijen as P
33+import qualified Elm.Compiler.Version as Compiler
34+import qualified Elm.Package as Pkg
35+import qualified Json.Encode as E
42+fromString :: String -> P.Doc
47+fromText :: Text.Text -> P.Doc
49+ P.text (Text.unpack txt)
52+fromName :: N.Name -> P.Doc
54+ P.text (N.toString name)
61+toAnsi :: Handle -> P.Doc -> IO ()
63+ P.displayIO handle (P.renderPretty 1 80 doc)
66+toString :: P.Doc -> String
68+ P.displayS (P.renderPretty 1 80 doc) ""
71+toLine :: P.Doc -> String
73+ P.displayS (P.renderPretty 1 (div maxBound 2) doc) ""
80+stack :: [P.Doc] -> P.Doc
82+ P.vcat (List.intersperse "" docs)
85+reflow :: String -> P.Doc
87+ P.fillSep (map P.text (words paragraph))
90+commaSep :: P.Doc -> (P.Doc -> P.Doc) -> [P.Doc] -> [P.Doc]
91+commaSep conjunction addStyle names =
97+ [ addStyle name1, conjunction, addStyle name2 ]
100+ map (\name -> addStyle name <> ",") (init names)
103+ , addStyle (last names)
111+toSimpleNote :: String -> P.Doc
112+toSimpleNote message =
113+ P.fillSep ((P.underline "Note" <> ":") : map P.text (words message))
116+toSimpleHint :: String -> P.Doc
117+toSimpleHint message =
118+ toFancyHint (map P.text (words message))
121+toFancyHint :: [P.Doc] -> P.Doc
123+ P.fillSep (P.underline "Hint" <> ":" : chunks)
130+link :: P.Doc -> String -> String -> String -> P.Doc
131+link word before fileName after =
133+ (P.underline word <> ":")
134+ : map P.text (words before)
135+ ++ P.text (makeLink fileName)
136+ : map P.text (words after)
139+fancyLink :: P.Doc -> [P.Doc] -> String -> [P.Doc] -> P.Doc
140+fancyLink word before fileName after =
142+ (P.underline word <> ":") : before ++ P.text (makeLink fileName) : after
145+makeLink :: String -> String
147+ "<https://elm-lang.org/hints/" <> Pkg.versionToString Compiler.version <> "/" <> fileName <> ">"
150+reflowLink :: String -> String -> String -> P.Doc
151+reflowLink before fileName after =
153+ map P.text (words before)
154+ ++ P.text (makeLink fileName)
155+ : map P.text (words after)
162+args :: Int -> String
164+ show n <> if n == 1 then " argument" else " arguments"
167+moreArgs :: Int -> String
169+ show n <> " more" <> if n == 1 then " argument" else " arguments"
172+ordinalize :: Int -> String
182+ | remainder100 `elem` [11..13] = "th"
183+ | remainder10 == 1 = "st"
184+ | remainder10 == 2 = "nd"
185+ | remainder10 == 3 = "rd"
188+ show number <> ending
192+cycle :: Int -> [N.Name] -> P.Doc
196+ nameLine name = "│ " <> P.dullyellow (fromName name)
198+ bottomLine = "└─────┘"
200+ P.indent indent $ P.vcat $
201+ topLine : List.intersperse midLine (map nameLine names) ++ [ bottomLine ]
208+encode :: P.Doc -> E.Value
210+ E.array (toJsonHelp noStyle [] (P.renderPretty 1 80 doc))
216+ , _underline :: Bool
217+ , _color :: Maybe Color
223+ Style False False Nothing
245+toJsonHelp :: Style -> [TB.Builder] -> P.SimpleDoc -> [E.Value]
246+toJsonHelp style revChunks simpleDoc =
250+ "according to the main implementation, @SFail@ can not\
251+ \ appear uncaught in a rendered @SimpleDoc@"
254+ [ encodeChunks style revChunks ]
256+ P.SChar char rest ->
257+ toJsonHelp style (TB.singleton char : revChunks) rest
259+ P.SText _ string rest ->
260+ toJsonHelp style (TB.fromString string : revChunks) rest
262+ P.SLine indent rest ->
263+ toJsonHelp style (spaces indent : "\n" : revChunks) rest
266+ encodeChunks style revChunks : toJsonHelp (sgrToStyle sgrs style) [] rest
269+spaces :: Int -> TB.Builder
271+ TB.fromText (Text.replicate n " ")
274+sgrToStyle :: [Ansi.SGR] -> Style -> Style
275+sgrToStyle sgrs style@(Style bold underline color) =
283+ Ansi.Reset -> noStyle
284+ Ansi.SetConsoleIntensity i -> Style (isBold i) underline color
285+ Ansi.SetItalicized _ -> style
286+ Ansi.SetUnderlining u -> Style bold (isUnderline u) color
287+ Ansi.SetBlinkSpeed _ -> style
288+ Ansi.SetVisible _ -> style
289+ Ansi.SetSwapForegroundBackground _ -> style
290+ Ansi.SetColor l i c -> Style bold underline (toColor l i c)
291+ Ansi.SetRGBColor _ _ -> style
294+isBold :: Ansi.ConsoleIntensity -> Bool
297+ Ansi.BoldIntensity -> True
298+ Ansi.FaintIntensity -> False
299+ Ansi.NormalIntensity -> False
302+isUnderline :: Ansi.Underlining -> Bool
303+isUnderline underlining =
305+ Ansi.SingleUnderline -> True
306+ Ansi.DoubleUnderline -> False
307+ Ansi.NoUnderline -> False
310+toColor :: Ansi.ConsoleLayer -> Ansi.ColorIntensity -> Ansi.Color -> Maybe Color
311+toColor layer intensity color =
325+ Ansi.Red -> pick D_Red V_Red
326+ Ansi.Magenta -> pick D_Magenta V_Magenta
327+ Ansi.Yellow -> pick D_Yellow V_Yellow
328+ Ansi.Green -> pick D_Green V_Green
329+ Ansi.Cyan -> pick D_Cyan V_Cyan
330+ Ansi.Blue -> pick D_Blue V_Blue
331+ Ansi.White -> pick D_White V_White
332+ Ansi.Black -> pick D_Black V_Black
335+encodeChunks :: Style -> [TB.Builder] -> E.Value
336+encodeChunks (Style bold underline color) revChunks =
344+ TL.toStrict $ TB.toLazyText $
345+ List.foldl' (\builder chunk -> chunk <> builder) c cs
348+ Nothing | not bold && not underline ->
353+ [ ("bold", E.bool bold)
354+ , ("underline", E.bool underline)
355+ , ("color", maybe E.null encodeColor color)
356+ , ("string", E.text text)
360+encodeColor :: Color -> E.Value
366+ D_Magenta -> "magenta"
367+ V_Magenta -> "MAGENTA"
368+ D_Yellow -> "yellow"
369+ V_Yellow -> "YELLOW"