1{-# OPTIONS_GHC -Wall #-}
2module Reporting.Error.Helpers
5 , hintLink, stack, reflowParagraph
6 , commaSep, capitalize, ordinalize, drawCycle
7 , findPotentialTypos, findTypoPairs, vetTypos
8 , nearbyNames, distance, maybeYouWant
12import Data.Function (on)
13import qualified Data.Char as Char
14import qualified Data.List as List
15import qualified Data.Map as Map
16import qualified Data.Set as Set
17import qualified Text.EditDistance as Dist
18import Text.PrettyPrint.ANSI.Leijen
19 ( Doc, (<>), dullyellow, fillSep, hardline, text, vcat )
21import qualified AST.Helpers as Help
22import qualified Elm.Compiler.Version as Compiler
23import qualified Elm.Package as Pkg
30(|>) :: a -> (a -> b) -> b
42functionName :: String -> String
44 if Help.isOp opName then
53 show n ++ if n == 1 then " argument" else " arguments"
56hintLink :: String -> String
58 "<https://github.com/elm-lang/elm-compiler/blob/"
59 ++ Pkg.versionToString Compiler.version
60 ++ "/hints/" ++ fileName ++ ".md>"
67 error "function `stack` requires a non-empty list of docs"
70 List.foldl' (\a b -> a <> hardline <> hardline <> b) doc docs
73reflowParagraph :: String -> Doc
74reflowParagraph paragraph =
75 fillSep (map text (words paragraph))
78commaSep :: [String] -> String
85 " " ++ token1 ++ " and " ++ token2
88 " " ++ List.intercalate ", " (init tokens) ++ ", and " ++ last tokens
91capitalize :: String -> String
99ordinalize :: Int -> String
109 | remainder100 `elem` [11..13] = "th"
110 | remainder10 == 1 = "st"
111 | remainder10 == 2 = "nd"
112 | remainder10 == 3 = "rd"
115 show number ++ ending
119drawCycle :: [String] -> Doc
126 text "│ " <> dullyellow (text str)
134 vcat (topLine : List.intersperse midLine (map line strings) ++ [ bottomLine ])
141findPotentialTypos :: [String] -> String -> [String]
142findPotentialTypos knownNames badName =
143 filter ((==1) . distance badName) knownNames
146findTypoPairs :: [String] -> [String] -> [(String, String)]
147findTypoPairs leftOnly rightOnly =
150 map ((,) leftName) (findPotentialTypos rightOnly leftName)
152 concatMap veryNear leftOnly
155vetTypos :: [(String, String)] -> Maybe (Set.Set String, Set.Set String)
156vetTypos potentialTypos =
158 tallyNames (ln, rn) (lc, rc) =
159 ( Map.insertWith (+) ln 1 lc
160 , Map.insertWith (+) rn 1 rc
163 (leftCounts, rightCounts) =
164 foldr tallyNames (Map.empty, Map.empty) potentialTypos
166 acceptable :: Map.Map String Int -> Bool
168 not (Map.null counts)
170 Map.foldr (\n unique -> n < 2 && unique) True counts
172 if acceptable leftCounts && acceptable rightCounts then
173 Just (Map.keysSet leftCounts, Map.keysSet rightCounts)
183nearbyNames :: (a -> String) -> a -> [a] -> [a]
184nearbyNames format name names =
186 if length (format name) < 3 then 1 else 2
189 |> map (\x -> (distance (format name) (format x), x))
190 |> List.sortBy (compare `on` fst)
191 |> filter ( (<= editDistance) . abs . fst )
195distance :: String -> String -> Int
197 Dist.restrictedDamerauLevenshteinDistance Dist.defaultEditCosts x y
200maybeYouWant :: [String] -> String
201maybeYouWant suggestions =
207 "Maybe you want one of the following?\n"
208 ++ concatMap ("\n "++) (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