on 780ee73 help sign in
elk/src/Reporting/Error/Helpers.hs
158 lines 3.2 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2module Reporting.Error.Helpers
3 ( (|>)
4 , functionName, hintLink, stack, reflowParagraph
5 , commaSep, capitalize, ordinalize, drawCycle
6 , nearbyNames, distance, maybeYouWant
7 )
8 where
10import Data.Function (on)
11import qualified Data.Char as Char
12import qualified Data.List as List
13import qualified Text.EditDistance as Dist
14import Text.PrettyPrint.ANSI.Leijen
15 ( Doc, (<>), dullyellow, fillSep, hardline, text, vcat )
17import qualified AST.Helpers as Help
18import qualified Elm.Compiler.Version as Compiler
19import qualified Elm.Package as Pkg
23-- PIPES
26(|>) :: a -> (a -> b) -> b
27(|>) x f =
28 f x
31infixl 0 |>
35-- DOC HELPERS
38functionName :: String -> String
39functionName opName =
40 if Help.isOp opName then
41 "(" ++ opName ++ ")"
43 else
44 "`" ++ opName ++ "`"
47hintLink :: String -> String
48hintLink fileName =
49 "<https://github.com/elm-lang/elm-compiler/blob/"
50 ++ Pkg.versionToString Compiler.version
51 ++ "/hints/" ++ fileName ++ ".md>"
54stack :: [Doc] -> Doc
55stack list =
56 case list of
57 [] ->
58 error "function `stack` requires a non-empty list of docs"
60 doc : docs ->
61 List.foldl' (\a b -> a <> hardline <> hardline <> b) doc docs
64reflowParagraph :: String -> Doc
65reflowParagraph paragraph =
66 fillSep (map text (words paragraph))
69commaSep :: [String] -> String
70commaSep tokens =
71 case tokens of
72 [token] ->
73 " " ++ token
75 [token1,token2] ->
76 " " ++ token1 ++ " and " ++ token2
78 _ ->
79 " " ++ List.intercalate ", " (init tokens) ++ ", and " ++ last tokens
82capitalize :: String -> String
83capitalize string =
84 case string of
85 [] -> []
86 c : cs ->
87 Char.toUpper c : cs
90ordinalize :: Int -> String
91ordinalize number =
92 let
93 remainder10 =
94 number `mod` 10
96 remainder100 =
97 number `mod` 100
99 ending
100 | remainder100 `elem` [11..13] = "th"
101 | remainder10 == 1 = "st"
102 | remainder10 == 2 = "nd"
103 | remainder10 == 3 = "rd"
104 | otherwise = "th"
105 in
106 show number ++ ending
110drawCycle :: [String] -> Doc
111drawCycle strings =
112 let
113 topLine =
114 text "┌─────┐"
116 line str =
117 text "│ " <> dullyellow (text str)
119 midLine =
120 text "│ ↓"
122 bottomLine =
123 text "└─────┘"
124 in
125 vcat (topLine : List.intersperse midLine (map line strings) ++ [ bottomLine ])
129-- NEARBY NAMES
132nearbyNames :: (a -> String) -> a -> [a] -> [a]
133nearbyNames format name names =
134 let editDistance =
135 if length (format name) < 3 then 1 else 2
136 in
137 names
138 |> map (\x -> (distance (format name) (format x), x))
139 |> List.sortBy (compare `on` fst)
140 |> filter ( (<= editDistance) . abs . fst )
141 |> map snd
144distance :: String -> String -> Int
145distance x y =
146 Dist.restrictedDamerauLevenshteinDistance Dist.defaultEditCosts x y
149maybeYouWant :: [String] -> String
150maybeYouWant suggestions =
151 case suggestions of
152 [] ->
153 ""
155 _:_ ->
156 "Maybe you want one of the following?\n"
157 ++ concatMap ("\n "++) (take 4 suggestions)