1{-# OPTIONS_GHC -Wall #-}
2module Reporting.Error.Helpers
4 , functionName, hintLink, stack, reflowParagraph
5 , commaSep, capitalize, ordinalize, drawCycle
6 , findPotentialTypos, vetTypos
7 , nearbyNames, distance, maybeYouWant
11import Data.Function (on)
12import qualified Data.Char as Char
13import qualified Data.List as List
14import qualified Data.Map as Map
15import qualified Data.Set as Set
16import qualified Text.EditDistance as Dist
17import Text.PrettyPrint.ANSI.Leijen
18 ( Doc, (<>), dullyellow, fillSep, hardline, text, vcat )
20import qualified AST.Helpers as Help
21import qualified Elm.Compiler.Version as Compiler
22import qualified Elm.Package as Pkg
29(|>) :: a -> (a -> b) -> b
41functionName :: String -> String
43 if Help.isOp opName then
50hintLink :: String -> String
52 "<https://github.com/elm-lang/elm-compiler/blob/"
53 ++ Pkg.versionToString Compiler.version
54 ++ "/hints/" ++ fileName ++ ".md>"
61 error "function `stack` requires a non-empty list of docs"
64 List.foldl' (\a b -> a <> hardline <> hardline <> b) doc docs
67reflowParagraph :: String -> Doc
68reflowParagraph paragraph =
69 fillSep (map text (words paragraph))
72commaSep :: [String] -> String
79 " " ++ token1 ++ " and " ++ token2
82 " " ++ List.intercalate ", " (init tokens) ++ ", and " ++ last tokens
85capitalize :: String -> String
93ordinalize :: Int -> String
103 | remainder100 `elem` [11..13] = "th"
104 | remainder10 == 1 = "st"
105 | remainder10 == 2 = "nd"
106 | remainder10 == 3 = "rd"
109 show number ++ ending
113drawCycle :: [String] -> Doc
122 [ text "│ " <> dullyellow (text str)
133 vcat (topLine ++ List.intercalate midLine (map line strings) ++ [ bottomLine ])
140findPotentialTypos :: [String] -> [String] -> [(String, String)]
141findPotentialTypos leftOnly rightOnly =
144 map ((,) leftName) (filter ((==1) . distance leftName) rightOnly)
146 concatMap veryNear leftOnly
149vetTypos :: [(String, String)] -> Maybe (Set.Set String, Set.Set String)
150vetTypos potentialTypos =
152 tallyNames (ln, rn) (lc, rc) =
153 ( Map.insertWith (+) ln 1 lc
154 , Map.insertWith (+) rn 1 rc
157 (leftCounts, rightCounts) =
158 foldr tallyNames (Map.empty, Map.empty) potentialTypos
160 acceptable :: Map.Map String Int -> Bool
162 not (Map.null counts)
164 Map.foldr (\n unique -> n < 2 && unique) True counts
166 if acceptable leftCounts && acceptable rightCounts then
167 Just (Map.keysSet leftCounts, Map.keysSet rightCounts)
177nearbyNames :: (a -> String) -> a -> [a] -> [a]
178nearbyNames format name names =
180 if length (format name) < 3 then 1 else 2
183 |> map (\x -> (distance (format name) (format x), x))
184 |> List.sortBy (compare `on` fst)
185 |> filter ( (<= editDistance) . abs . fst )
189distance :: String -> String -> Int
191 Dist.restrictedDamerauLevenshteinDistance Dist.defaultEditCosts x y
194maybeYouWant :: [String] -> String
195maybeYouWant suggestions =
201 "Maybe you want one of the following?\n"
202 ++ 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