@@ -1,21 +1,22 @@
1{-# OPTIONS_GHC -Wall #-}
1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Helpers
3module Reporting.Helpers
5− -- re-exports
5+ , nameToDoc
6− , Doc, (<+>), (<>), cat, dullyellow, fillSep, green, hang
7− , hsep, indent, parens, sep, text, underline, vcat
10− , functionName, args, moreArgs
6+ , args, moreArgs
11− , toSimpleHint, toFancyHint, hintLink
7+ , toSimpleNote, toSimpleHint, toFancyHint
12− , stack, reflowParagraph
8+ , link, reflowLink
13 , commaSep, capitalize, ordinalize, drawCycle
10 , commaSep, capitalize, ordinalize, drawCycle
14 , findPotentialTypos, findTypoPairs, vetTypos
11 , findPotentialTypos, findTypoPairs, vetTypos
15 , nearbyNames, distance, maybeYouWant, maybeYouWant'
12 , nearbyNames, distance, maybeYouWant, maybeYouWant'
14+ , Doc, (<+>), (<>), black, cat, dullyellow, fillSep, green, hang, hardline
15+ , hcat, hsep, indent, magenta, parens, sep, text, underline, vcat
19import Data.Function (on)
20import Data.Function (on)
20import qualified Data.Char as Char
21import qualified Data.Char as Char
21import qualified Data.List as List
22import qualified Data.List as List
@@ -24,67 +25,51 @@ import Data.Monoid ((<>))
24import qualified Data.Set as Set
25import qualified Data.Set as Set
25import qualified Data.Text as Text
26import qualified Data.Text as Text
26import Data.Text (Text)
27import Data.Text (Text)
28+import qualified Elm.Name as N
27import qualified Text.EditDistance as Dist
29import qualified Text.EditDistance as Dist
28import qualified Text.PrettyPrint.ANSI.Leijen as P
30import qualified Text.PrettyPrint.ANSI.Leijen as P
29−import Text.PrettyPrint.ANSI.Leijen hiding ((<>), text)
31+import Text.PrettyPrint.ANSI.Leijen hiding ((<>))
31−import qualified AST.Helpers as Help
32import qualified Elm.Compiler.Version as Compiler
33import qualified Elm.Compiler.Version as Compiler
33import qualified Elm.Package as Pkg
34import qualified Elm.Package as Pkg
40−(|>) :: a -> (a -> b) -> b
49-- DOC HELPERS
38-- DOC HELPERS
52−text :: Text -> Doc
41+textToDoc :: Text -> Doc
53−text msg =
42+textToDoc msg =
54− P.text (Text.unpack msg)
43+ text (Text.unpack msg)
57−i2t :: Int -> Text
46+nameToDoc :: N.Name -> Doc
58−i2t n =
47+nameToDoc name =
59− Text.pack (show n)
48+ text (N.toString name)
62−functionName :: Text -> Text
64− if Help.isOp opName then
71−args :: Int -> Text
51+args :: Int -> String
73− i2t n <> if n == 1 then " argument" else " arguments"
53+ show n <> if n == 1 then " argument" else " arguments"
76−moreArgs :: Int -> Text
56+moreArgs :: Int -> String
77moreArgs n =
57moreArgs n =
78− i2t n <> " more" <> if n == 1 then " argument" else " arguments"
58+ show n <> " more" <> if n == 1 then " argument" else " arguments"
65+toSimpleNote :: String -> Doc
66+toSimpleNote message =
67+ fillSep ((underline (text "Note") <> ":") : map text (words message))
85−toSimpleHint :: Text -> Doc
70+toSimpleHint :: String -> Doc
86−toSimpleHint txt =
71+toSimpleHint message =
87− toFancyHint (map text (Text.words txt))
72+ toFancyHint (map text (words message))
90toFancyHint :: [Doc] -> Doc
75toFancyHint :: [Doc] -> Doc
@@ -92,11 +77,26 @@ toFancyHint chunks =
92 fillSep (underline (text "Hint") <> ":" : chunks)
77 fillSep (underline (text "Hint") <> ":" : chunks)
95−hintLink :: Text -> Text
80+link :: Doc -> String -> String -> String -> Doc
81+link word before fileName after =
83+ (underline word <> ":")
84+ : map text (words before)
85+ ++ P.text (makeLink fileName)
86+ : map text (words after)
89+makeLink :: String -> String
96−hintLink fileName =
90+makeLink fileName =
97− "<https://github.com/elm-lang/elm-compiler/blob/"
98− <> Text.pack (Pkg.versionToString Compiler.version)
91+ "<http://elm-lang.org/hints/" <> Pkg.versionToString Compiler.version <> "/" <> fileName <> ".md>"
99− <> "/hints/" <> fileName <> ".md>"
92+
94+reflowLink :: String -> String -> String -> Doc
95+reflowLink before fileName after =
97+ map text (words before)
98+ ++ P.text (makeLink fileName)
99+ : map text (words after)
102stack :: [Doc] -> Doc
102stack :: [Doc] -> Doc
@@ -109,22 +109,26 @@ stack chunks =
109 List.foldl' (\a b -> a <> hardline <> hardline <> b) doc docs
109 List.foldl' (\a b -> a <> hardline <> hardline <> b) doc docs
112−reflowParagraph :: Text -> Doc
112+reflow :: String -> Doc
113−reflowParagraph paragraph =
113+reflow paragraph =
114− fillSep (map text (Text.words paragraph))
114+ fillSep (map text (words paragraph))
117−commaSep :: [Text] -> Text
117+commaSep :: Doc -> (Doc -> Doc) -> [Doc] -> [Doc]
118−commaSep tokens =
118+commaSep conjunction addStyle names =
119− case tokens of
119+ case names of
120− [token] ->
120+ [name] ->
121− " " <> token
121+ [ addStyle name ]
123− [token1,token2] ->
123+ [name1,name2] ->
124− " " <> token1 <> " and " <> token2
124+ [ addStyle name1, conjunction, addStyle name2 ]
127− " " <> Text.intercalate ", " (init tokens) <> ", and " <> last tokens
127+ map (\name -> addStyle name <> ",") (init names)
130+ , addStyle (last names)
130capitalize :: Text -> Text
134capitalize :: Text -> Text
@@ -137,7 +141,7 @@ capitalize txt =
137 Text.cons (Char.toUpper c) rest
141 Text.cons (Char.toUpper c) rest
140−ordinalize :: Int -> Text
144+ordinalize :: Int -> String
141ordinalize number =
145ordinalize number =
143 remainder10 =
147 remainder10 =
@@ -153,24 +157,24 @@ ordinalize number =
153 | remainder10 == 3 = "rd"
157 | remainder10 == 3 = "rd"
154 | otherwise = "th"
158 | otherwise = "th"
156− i2t number <> ending
160+ show number <> ending
160−drawCycle :: [Text] -> Doc
164+drawCycle :: [N.Name] -> Doc
161drawCycle names =
165drawCycle names =
163 topLine =
167 topLine =
164− text "┌─────┐"
168+ "┌─────┐"
166 nameLine name =
170 nameLine name =
167− text "│ " <> dullyellow (text name)
171+ "│ " <> dullyellow (textToDoc name)
169 midLine =
173 midLine =
170− text "│ ↓"
174+ "│ ↓"
172 bottomLine =
176 bottomLine =
173− text "└─────┘"
177+ "└─────┘"
175 vcat (topLine : List.intersperse midLine (map nameLine names) ++ [ bottomLine ])
179 vcat (topLine : List.intersperse midLine (map nameLine names) ++ [ bottomLine ])
@@ -179,12 +183,12 @@ drawCycle names =
179-- FIND TYPOS
183-- FIND TYPOS
182−findPotentialTypos :: [Text] -> Text -> [Text]
186+findPotentialTypos :: [String] -> String -> [String]
183findPotentialTypos knownNames badName =
187findPotentialTypos knownNames badName =
184 filter ((==1) . distance badName) knownNames
188 filter ((==1) . distance badName) knownNames
187−findTypoPairs :: [Text] -> [Text] -> [(Text, Text)]
191+findTypoPairs :: [String] -> [String] -> [(String, String)]
188findTypoPairs leftOnly rightOnly =
192findTypoPairs leftOnly rightOnly =
190 veryNear leftName =
194 veryNear leftName =
@@ -193,7 +197,7 @@ findTypoPairs leftOnly rightOnly =
193 concatMap veryNear leftOnly
197 concatMap veryNear leftOnly
196−vetTypos :: [(Text, Text)] -> Maybe (Set.Set Text, Set.Set Text)
200+vetTypos :: [(String, String)] -> Maybe (Set.Set String, Set.Set String)
197vetTypos potentialTypos =
201vetTypos potentialTypos =
199 tallyNames (ln, rn) (lc, rc) =
203 tallyNames (ln, rn) (lc, rc) =
@@ -204,7 +208,7 @@ vetTypos potentialTypos =
204 (leftCounts, rightCounts) =
208 (leftCounts, rightCounts) =
205 foldr tallyNames (Map.empty, Map.empty) potentialTypos
209 foldr tallyNames (Map.empty, Map.empty) potentialTypos
207− acceptable :: Map.Map Text Int -> Bool
211+ acceptable :: Map.Map String Int -> Bool
208 acceptable counts =
212 acceptable counts =
209 not (Map.null counts)
213 not (Map.null counts)
@@ -221,32 +225,28 @@ vetTypos potentialTypos =
221-- NEARBY NAMES
225-- NEARBY NAMES
224−nearbyNames :: (a -> Text) -> a -> [a] -> [a]
228+nearbyNames :: (a -> String) -> a -> [a] -> [a]
225nearbyNames format name names =
229nearbyNames format name names =
226 let editDistance =
230 let editDistance =
227− if Text.length (format name) < 3 then 1 else 2
231+ if length (format name) < 3 then 1 else 2
234+ filter ( (<= editDistance) . abs . fst ) $
235+ List.sortBy (compare `on` fst) $
230− |> map (\x -> (distance (format name) (format x), x))
236+ map (\x -> (distance (format name) (format x), x)) names
231− |> List.sortBy (compare `on` fst)
232− |> filter ( (<= editDistance) . abs . fst )
236−distance :: Text -> Text -> Int
239+distance :: String -> String -> Int
237distance x y =
240distance x y =
238− Dist.restrictedDamerauLevenshteinDistance
241+ Dist.restrictedDamerauLevenshteinDistance Dist.defaultEditCosts x y
239− Dist.defaultEditCosts
244−maybeYouWant :: Maybe Doc -> [Text] -> Doc
244+maybeYouWant :: Maybe Doc -> [N.Name] -> Doc
245maybeYouWant maybeStarter suggestions =
245maybeYouWant maybeStarter suggestions =
246 maybe P.empty id (maybeYouWant' maybeStarter suggestions)
246 maybe P.empty id (maybeYouWant' maybeStarter suggestions)
249−maybeYouWant' :: Maybe Doc -> [Text] -> Maybe Doc
249+maybeYouWant' :: Maybe Doc -> [N.Name] -> Maybe Doc
250maybeYouWant' maybeStarter suggestions =
250maybeYouWant' maybeStarter suggestions =
251 case suggestions of
251 case suggestions of
@@ -255,5 +255,5 @@ maybeYouWant' maybeStarter suggestions =
256 Just $ stack $
256 Just $ stack $
257 [ maybe id (<+>) maybeStarter "Maybe you want one of the following?"
257 [ maybe id (<+>) maybeStarter "Maybe you want one of the following?"
258− , P.indent 4 $ P.vcat $ map (P.dullyellow . text) (take 4 suggestions)
258+ , P.indent 4 $ P.vcat $ map (P.dullyellow . nameToDoc) (take 4 suggestions)