1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Helpers
7 , toSimpleNote, toSimpleHint, toFancyHint
10 , commaSep, capitalize, ordinalize, drawCycle
11 , findPotentialTypos, findTypoPairs, vetTypos
12 , nearbyNames, distance, maybeYouWant, maybeYouWant'
14 , Doc, (<+>), (<>), black, cat, dullyellow, fillSep, green, hang, hardline
15 , hcat, hsep, indent, magenta, parens, sep, text, underline, vcat
20import Data.Function (on)
21import qualified Data.Char as Char
22import qualified Data.List as List
23import qualified Data.Map as Map
24import Data.Monoid ((<>))
25import qualified Data.Set as Set
26import qualified Data.Text as Text
27import Data.Text (Text)
28import qualified Elm.Name as N
29import qualified Text.EditDistance as Dist
30import qualified Text.PrettyPrint.ANSI.Leijen as P
31import Text.PrettyPrint.ANSI.Leijen hiding ((<>))
33import qualified Elm.Compiler.Version as Compiler
34import qualified Elm.Package as Pkg
41textToDoc :: Text -> Doc
43 text (Text.unpack msg)
46nameToDoc :: N.Name -> Doc
48 text (N.toString name)
53 show n <> if n == 1 then " argument" else " arguments"
56moreArgs :: Int -> String
58 show n <> " more" <> if n == 1 then " argument" else " arguments"
65toSimpleNote :: String -> Doc
67 fillSep ((underline (text "Note") <> ":") : map text (words message))
70toSimpleHint :: String -> Doc
72 toFancyHint (map text (words message))
75toFancyHint :: [Doc] -> Doc
77 fillSep (underline (text "Hint") <> ":" : chunks)
80link :: Doc -> String -> String -> String -> Doc
81link word before fileName after =
83 (underline word <> ":")
84 : map text (words before)
85 ++ P.text (makeLink fileName)
86 : map text (words after)
89makeLink :: String -> String
91 "<http://elm-lang.org/hints/" <> Pkg.versionToString Compiler.version <> "/" <> fileName <> ".md>"
94reflowLink :: String -> String -> String -> Doc
95reflowLink before fileName after =
97 map text (words before)
98 ++ P.text (makeLink fileName)
99 : map text (words after)
106 error "function `stack` requires a non-empty list of docs"
109 List.foldl' (\a b -> a <> hardline <> hardline <> b) doc docs
112reflow :: String -> Doc
114 fillSep (map text (words paragraph))
117commaSep :: Doc -> (Doc -> Doc) -> [Doc] -> [Doc]
118commaSep conjunction addStyle names =
124 [ addStyle name1, conjunction, addStyle name2 ]
127 map (\name -> addStyle name <> ",") (init names)
130 , addStyle (last names)
134capitalize :: Text -> Text
136 case Text.uncons txt of
141 Text.cons (Char.toUpper c) rest
144ordinalize :: Int -> String
154 | remainder100 `elem` [11..13] = "th"
155 | remainder10 == 1 = "st"
156 | remainder10 == 2 = "nd"
157 | remainder10 == 3 = "rd"
160 show number <> ending
164drawCycle :: [N.Name] -> Doc
171 "│ " <> dullyellow (textToDoc name)
179 vcat (topLine : List.intersperse midLine (map nameLine names) ++ [ bottomLine ])
186findPotentialTypos :: [String] -> String -> [String]
187findPotentialTypos knownNames badName =
188 filter ((==1) . distance badName) knownNames
191findTypoPairs :: [String] -> [String] -> [(String, String)]
192findTypoPairs leftOnly rightOnly =
195 map ((,) leftName) (findPotentialTypos rightOnly leftName)
197 concatMap veryNear leftOnly
200vetTypos :: [(String, String)] -> Maybe (Set.Set String, Set.Set String)
201vetTypos potentialTypos =
203 tallyNames (ln, rn) (lc, rc) =
204 ( Map.insertWith (+) ln 1 lc
205 , Map.insertWith (+) rn 1 rc
208 (leftCounts, rightCounts) =
209 foldr tallyNames (Map.empty, Map.empty) potentialTypos
211 acceptable :: Map.Map String Int -> Bool
213 not (Map.null counts)
215 Map.foldr (\n unique -> n < 2 && unique) True counts
217 if acceptable leftCounts && acceptable rightCounts then
218 Just (Map.keysSet leftCounts, Map.keysSet rightCounts)
228nearbyNames :: (a -> String) -> a -> [a] -> [a]
229nearbyNames format name names =
231 if length (format name) < 3 then 1 else 2
234 filter ( (<= editDistance) . abs . fst ) $
235 List.sortBy (compare `on` fst) $
236 map (\x -> (distance (format name) (format x), x)) names
239distance :: String -> String -> Int
241 Dist.restrictedDamerauLevenshteinDistance Dist.defaultEditCosts x y
244maybeYouWant :: Maybe Doc -> [N.Name] -> Doc
245maybeYouWant maybeStarter suggestions =
246 maybe P.empty id (maybeYouWant' maybeStarter suggestions)
249maybeYouWant' :: Maybe Doc -> [N.Name] -> Maybe Doc
250maybeYouWant' maybeStarter suggestions =
257 [ maybe id (<+>) maybeStarter "Maybe you want one of the following?"
258 , P.indent 4 $ P.vcat $ map (P.dullyellow . nameToDoc) (take 4 suggestions)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list