@@ -1,6 +1,5 @@
11{-# LANGUAGE GeneralizedNewtypeDeriving #-}
22{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE RecordWildCards #-}
43{-# LANGUAGE MultiParamTypeClasses #-}
54
65module Language.PureScript.Errors where
@@ -9,6 +8,7 @@ import Prelude ()
98import Prelude.Compat
109
1110import Data.Ord (comparing)
11+import Data.Char (isSpace)
1212import Data.Either (lefts, rights)
1313import Data.List (intercalate, transpose, nub, nubBy, sortBy)
1414import Data.Foldable (fold)
@@ -53,63 +53,63 @@ data SimpleErrorMessage
5353 | RedefinedIdent Ident
5454 | OverlappingNamesInLet
5555 | UnknownModule ModuleName
56− | UnknownType (Qualified ProperName)
57− | UnknownTypeClass (Qualified ProperName)
56+ | UnknownType (Qualified (ProperName 'TypeName))
57+ | UnknownTypeClass (Qualified (ProperName 'ClassName))
5858 | UnknownValue (Qualified Ident)
59− | UnknownDataConstructor (Qualified ProperName) (Maybe (Qualified ProperName))
60− | UnknownTypeConstructor (Qualified ProperName)
61− | UnknownImportType ModuleName ProperName
62− | UnknownExportType ProperName
63− | UnknownImportTypeClass ModuleName ProperName
64− | UnknownExportTypeClass ProperName
59+ | UnknownDataConstructor (Qualified (ProperName 'ConstructorName)) (Maybe (Qualified (ProperName 'ConstructorName)))
60+ | UnknownTypeConstructor (Qualified (ProperName 'TypeName))
61+ | UnknownImportType ModuleName (ProperName 'TypeName)
62+ | UnknownExportType (ProperName 'TypeName)
63+ | UnknownImportTypeClass ModuleName (ProperName 'ClassName)
64+ | UnknownExportTypeClass (ProperName 'ClassName)
6565 | UnknownImportValue ModuleName Ident
6666 | UnknownExportValue Ident
6767 | UnknownExportModule ModuleName
68− | UnknownImportDataConstructor ModuleName ProperName ProperName
69− | UnknownExportDataConstructor ProperName ProperName
68+ | UnknownImportDataConstructor ModuleName (ProperName 'TypeName) (ProperName 'ConstructorName)
69+ | UnknownExportDataConstructor (ProperName 'TypeName) (ProperName 'ConstructorName)
7070 | ScopeConflict String [ModuleName]
71− | ConflictingTypeDecls ProperName
72− | ConflictingCtorDecls ProperName
73− | TypeConflictsWithClass ProperName
74− | CtorConflictsWithClass ProperName
75− | ClassConflictsWithType ProperName
76− | ClassConflictsWithCtor ProperName
71+ | ConflictingTypeDecls (ProperName 'TypeName)
72+ | ConflictingCtorDecls (ProperName 'ConstructorName)
73+ | TypeConflictsWithClass (ProperName 'TypeName)
74+ | CtorConflictsWithClass (ProperName 'ConstructorName)
75+ | ClassConflictsWithType (ProperName 'ClassName)
76+ | ClassConflictsWithCtor (ProperName 'ClassName)
7777 | DuplicateModuleName ModuleName
78− | DuplicateClassExport ProperName
78+ | DuplicateClassExport (ProperName 'ClassName)
7979 | DuplicateValueExport Ident
8080 | DuplicateTypeArgument String
8181 | InvalidDoBind
8282 | InvalidDoLet
8383 | CycleInDeclaration Ident
84− | CycleInTypeSynonym (Maybe ProperName)
84+ | CycleInTypeSynonym (Maybe (ProperName 'TypeName))
8585 | CycleInModules [ModuleName]
8686 | NameIsUndefined Ident
87− | UndefinedTypeVariable ProperName
88− | PartiallyAppliedSynonym (Qualified ProperName)
87+ | UndefinedTypeVariable (ProperName 'TypeName)
88+ | PartiallyAppliedSynonym (Qualified (ProperName 'TypeName))
8989 | EscapedSkolem (Maybe Expr)
9090 | TypesDoNotUnify Type Type
9191 | KindsDoNotUnify Kind Kind
9292 | ConstrainedTypeUnified Type Type
93− | OverlappingInstances (Qualified ProperName) [Type] [Qualified Ident]
94− | NoInstanceFound (Qualified ProperName) [Type]
95− | PossiblyInfiniteInstance (Qualified ProperName) [Type]
96− | CannotDerive (Qualified ProperName) [Type]
97− | CannotFindDerivingType ProperName
93+ | OverlappingInstances (Qualified (ProperName 'ClassName)) [Type] [Qualified Ident]
94+ | NoInstanceFound (Qualified (ProperName 'ClassName)) [Type]
95+ | PossiblyInfiniteInstance (Qualified (ProperName 'ClassName)) [Type]
96+ | CannotDerive (Qualified (ProperName 'ClassName)) [Type]
97+ | CannotFindDerivingType (ProperName 'TypeName)
9898 | DuplicateLabel String (Maybe Expr)
9999 | DuplicateValueDeclaration Ident
100100 | ArgListLengthsDiffer Ident
101101 | OverlappingArgNames (Maybe Ident)
102102 | MissingClassMember Ident
103− | ExtraneousClassMember Ident (Qualified ProperName)
103+ | ExtraneousClassMember Ident (Qualified (ProperName 'ClassName))
104104 | ExpectedType Type Kind
105− | IncorrectConstructorArity (Qualified ProperName)
105+ | IncorrectConstructorArity (Qualified (ProperName 'ConstructorName))
106106 | ExprDoesNotHaveType Expr Type
107107 | PropertyIsMissing String
108108 | AdditionalProperty String
109109 | CannotApplyFunction Type Expr
110110 | TypeSynonymInstance
111− | OrphanInstance Ident (Qualified ProperName) [Type]
112− | InvalidNewtype ProperName
111+ | OrphanInstance Ident (Qualified (ProperName 'ClassName)) [Type]
112+ | InvalidNewtype (ProperName 'TypeName)
113113 | InvalidInstanceHead Type
114114 | TransitiveExportError DeclarationRef [DeclarationRef]
115115 | ShadowedName Ident
@@ -120,17 +120,17 @@ data SimpleErrorMessage
120120 | NotExhaustivePattern [[Binder]] Bool
121121 | OverlappingPattern [[Binder]] Bool
122122 | IncompleteExhaustivityCheck
123− | ClassOperator ProperName Ident
124− | MisleadingEmptyTypeImport ModuleName ProperName
123+ | ClassOperator (ProperName 'ClassName) Ident
124+ | MisleadingEmptyTypeImport ModuleName (ProperName 'TypeName)
125125 | ImportHidingModule ModuleName
126126 | UnusedImport ModuleName
127− | UnusedExplicitImport ModuleName [String]
128− | UnusedDctorImport ProperName
129− | UnusedDctorExplicitImport ProperName [ProperName]
127+ | UnusedExplicitImport ModuleName [String] (Maybe ModuleName) [DeclarationRef]
128+ | UnusedDctorImport (ProperName 'TypeName)
129+ | UnusedDctorExplicitImport (ProperName 'TypeName) [ProperName 'ConstructorName]
130130 | DeprecatedOperatorDecl String
131131 | DeprecatedQualifiedSyntax ModuleName ModuleName
132− | DeprecatedClassImport ModuleName ProperName
133− | DeprecatedClassExport ProperName
132+ | DeprecatedClassImport ModuleName (ProperName 'ClassName)
133+ | DeprecatedClassExport (ProperName 'ClassName)
134134 | RedundantUnqualifiedImport ModuleName ImportDeclarationType
135135 | DuplicateSelectiveImport ModuleName
136136 | DuplicateImport ModuleName ImportDeclarationType (Maybe ModuleName)
@@ -138,7 +138,9 @@ data SimpleErrorMessage
138138 | DuplicateExportRef String
139139 | IntOutOfRange Integer String Integer Integer
140140 | RedundantEmptyHidingImport ModuleName
141+ | ImplicitQualifiedImport ModuleName ModuleName [DeclarationRef]
141142 | ImplicitImport ModuleName [DeclarationRef]
143+ | HidingImport ModuleName [DeclarationRef]
142144 | CaseBinderLengthDiffers Int [Binder]
143145 deriving (Show)
144146
@@ -147,7 +149,7 @@ data ErrorMessageHint
147149 = ErrorUnifyingTypes Type Type
148150 | ErrorInExpression Expr
149151 | ErrorInModule ModuleName
150− | ErrorInInstance (Qualified ProperName) [Type]
152+ | ErrorInInstance (Qualified (ProperName 'ClassName)) [Type]
151153 | ErrorInSubsumption Type Type
152154 | ErrorCheckingAccessor Expr String
153155 | ErrorCheckingType Expr Type
@@ -155,11 +157,11 @@ data ErrorMessageHint
155157 | ErrorCheckingGuard
156158 | ErrorInferringType Expr
157159 | ErrorInApplication Expr Type Expr
158− | ErrorInDataConstructor ProperName
159− | ErrorInTypeConstructor ProperName
160+ | ErrorInDataConstructor (ProperName 'ConstructorName)
161+ | ErrorInTypeConstructor (ProperName 'TypeName)
160162 | ErrorInBindingGroup [Ident]
161163 | ErrorInDataBindingGroup
162− | ErrorInTypeSynonym ProperName
164+ | ErrorInTypeSynonym (ProperName 'TypeName)
163165 | ErrorInValueDeclaration Ident
164166 | ErrorInTypeDeclaration Ident
165167 | ErrorInForeignImport Ident
@@ -177,6 +179,8 @@ data HintCategory
177179
178180data ErrorMessage = ErrorMessage [ErrorMessageHint] SimpleErrorMessage deriving (Show)
179181
182+newtype ErrorSuggestion = ErrorSuggestion String
183+
180184-- | Get the source span for an error
181185errorSpan :: ErrorMessage -> Maybe SourceSpan
182186errorSpan = findHint matchSpan
@@ -309,7 +313,9 @@ errorCode em = case unwrapErrorMessage em of
309313 DuplicateExportRef{} -> "DuplicateExportRef"
310314 IntOutOfRange{} -> "IntOutOfRange"
311315 RedundantEmptyHidingImport{} -> "RedundantEmptyHidingImport"
316+ ImplicitQualifiedImport{} -> "ImplicitQualifiedImport"
312317 ImplicitImport{} -> "ImplicitImport"
318+ HidingImport{} -> "HidingImport"
313319 CaseBinderLengthDiffers{} -> "CaseBinderLengthDiffers"
314320
315321-- |
@@ -412,11 +418,48 @@ onTypesInErrorMessageM f (ErrorMessage hints simple) = ErrorMessage <$> traverse
412418 gHint (ErrorInInstance cl ts) = ErrorInInstance cl <$> traverse f ts
413419 gHint other = pure other
414420
421+wikiUri :: ErrorMessage -> String
422+wikiUri e = "https://github.com/purescript/purescript/wiki/Error-Code-" ++ errorCode e
423+
424+-- TODO Other possible suggestions:
425+-- WildcardInferredType - source span not small enough
426+-- DuplicateSelectiveImport - would require 2 ranges to remove and 1 insert
427+-- DeprecatedClassExport, DeprecatedClassImport, would want to replace smaller span?
428+errorSuggestion :: SimpleErrorMessage -> Maybe ErrorSuggestion
429+errorSuggestion err = case err of
430+ UnusedImport{} -> emptySuggestion
431+ RedundantEmptyHidingImport{} -> emptySuggestion
432+ DuplicateImport{} -> emptySuggestion
433+ RedundantUnqualifiedImport{} -> emptySuggestion
434+ DeprecatedQualifiedSyntax name qualName -> suggest $
435+ "import " ++ runModuleName name ++ " as " ++ runModuleName qualName
436+ UnusedExplicitImport mn _ qual refs -> suggest $ importSuggestion mn refs qual
437+ ImplicitImport mn refs -> suggest $ importSuggestion mn refs Nothing
438+ ImplicitQualifiedImport mn asModule refs -> suggest $ importSuggestion mn refs (Just asModule)
439+ _ -> Nothing
440+
441+ where
442+ emptySuggestion = Just $ ErrorSuggestion ""
443+ suggest = Just . ErrorSuggestion
444+
445+ importSuggestion :: ModuleName -> [ DeclarationRef ] -> Maybe ModuleName -> String
446+ importSuggestion mn refs qual =
447+ "import " ++ runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")" ++ qstr qual
448+
449+ qstr :: Maybe ModuleName -> String
450+ qstr (Just mn) = " as " ++ runModuleName mn
451+ qstr Nothing = ""
452+
453+showSuggestion :: SimpleErrorMessage -> String
454+showSuggestion suggestion = case errorSuggestion suggestion of
455+ Just (ErrorSuggestion x) -> x
456+ _ -> ""
457+
415458-- |
416459-- Pretty print a single error, simplifying if necessary
417460--
418−prettyPrintSingleError :: Bool -> Level -> ErrorMessage -> Box.Box
419−prettyPrintSingleError full level e = flip evalState defaultUnknownMap $ do
461+prettyPrintSingleError :: Bool -> Level -> Bool -> ErrorMessage -> Box.Box
462+prettyPrintSingleError full level showWiki e = flip evalState defaultUnknownMap $ do
420463 em <- onTypesInErrorMessageM replaceUnknowns (if full then e else simplifyErrorMessage e)
421464 um <- get
422465 return (prettyPrintErrorMessage um em)
@@ -425,20 +468,19 @@ prettyPrintSingleError full level e = flip evalState defaultUnknownMap $ do
425468 -- Pretty print an ErrorMessage
426469 prettyPrintErrorMessage :: TypeMap -> ErrorMessage -> Box.Box
427470 prettyPrintErrorMessage typeMap (ErrorMessage hints simple) =
428− paras
471+ paras $
429472 [ foldr renderHint (indent (renderSimpleErrorMessage simple)) hints
430− , Box.moveDown 1 typeInformation
431− , Box.moveDown 1 $ paras [ line $ "See " ++ wikiUri ++ " for more information, "
432− , line $ "or to contribute content related to this " ++ levelText ++ "."
433− ]
473+ ] ++
474+ maybe [] (return . Box.moveDown 1) typeInformation ++
475+ [ Box.moveDown 1 $ paras [ line $ "See " ++ wikiUri e ++ " for more information, "
476+ , line $ "or to contribute content related to this " ++ levelText ++ "."
477+ ]
478+ | showWiki
434479 ]
435480 where
436− wikiUri :: String
437− wikiUri = "https://github.com/purescript/purescript/wiki/Error-Code-" ++ errorCode e
438−
439− typeInformation :: Box.Box
440− typeInformation | not (null types) = Box.hsep 1 Box.left [ line "where", paras types]
441− | otherwise = Box.emptyBox 0 0
481+ typeInformation :: Maybe Box.Box
482+ typeInformation | not (null types) = Just $ Box.hsep 1 Box.left [ line "where", paras types ]
483+ | otherwise = Nothing
442484 where
443485 types :: [Box.Box]
444486 types = map skolemInfo (M.elems (umSkolemMap typeMap)) ++
@@ -790,9 +832,11 @@ prettyPrintSingleError full level e = flip evalState defaultUnknownMap $ do
790832 renderSimpleErrorMessage (UnusedImport name) =
791833 line $ "The import of module " ++ runModuleName name ++ " is redundant"
792834
793− renderSimpleErrorMessage (UnusedExplicitImport name names) =
794− paras [ line $ "The import of module " ++ runModuleName name ++ " contains the following unused references:"
795− , indent $ paras $ map line names ]
835+ renderSimpleErrorMessage msg@(UnusedExplicitImport mn names _ _) =
836+ paras [ line $ "The import of module " ++ runModuleName mn ++ " contains the following unused references:"
837+ , indent $ paras $ map line names
838+ , line $ "It could be replaced with:"
839+ , indent $ line $ showSuggestion msg ]
796840
797841 renderSimpleErrorMessage (UnusedDctorImport name) =
798842 line $ "The import of type " ++ runProperName name ++ " includes data constructors but only the type is used"
@@ -854,8 +898,19 @@ prettyPrintSingleError full level e = flip evalState defaultUnknownMap $ do
854898 renderSimpleErrorMessage (RedundantEmptyHidingImport mn) =
855899 line $ "The import for module " ++ runModuleName mn ++ " is redundant as all members have been explicitly hidden."
856900
857− renderSimpleErrorMessage (ImplicitImport mn refs) =
901+ renderSimpleErrorMessage msg@(ImplicitQualifiedImport importedModule asModule _) =
902+ paras [ line $ "Module " ++ runModuleName importedModule ++ " was imported as " ++ runModuleName asModule ++ " with unspecified imports."
903+ , line $ "As there are multiple modules being imported as " ++ runModuleName asModule ++ ", consider using the explicit form:"
904+ , indent $ line $ showSuggestion msg
905+ ]
906+
907+ renderSimpleErrorMessage msg@(ImplicitImport mn _) =
858908 paras [ line $ "Module " ++ runModuleName mn ++ " has unspecified imports, consider using the explicit form: "
909+ , indent $ line $ showSuggestion msg
910+ ]
911+
912+ renderSimpleErrorMessage (HidingImport mn refs) =
913+ paras [ line $ "Module " ++ runModuleName mn ++ " has unspecified imports, consider using the inclusive form: "
859914 , indent $ line $ "import " ++ runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")"
860915 ]
861916
@@ -992,37 +1047,13 @@ prettyPrintSingleError full level e = flip evalState defaultUnknownMap $ do
9921047 paras :: [Box.Box] -> Box.Box
9931048 paras = Box.vcat Box.left
9941049
995− -- Pretty print and export declaration
996− prettyPrintExport :: DeclarationRef -> String
997− prettyPrintExport (TypeRef pn _) = runProperName pn
998− prettyPrintExport ref = prettyPrintRef ref
999−
1000− prettyPrintRef :: DeclarationRef -> String
1001− prettyPrintRef (TypeRef pn Nothing) = runProperName pn ++ "(..)"
1002− prettyPrintRef (TypeRef pn (Just [])) = runProperName pn
1003− prettyPrintRef (TypeRef pn (Just dctors)) = runProperName pn ++ "(" ++ intercalate ", " (map runProperName dctors) ++ ")"
1004− prettyPrintRef (ValueRef ident) = showIdent ident
1005− prettyPrintRef (TypeClassRef pn) = "class " ++ runProperName pn
1006− prettyPrintRef (ProperRef pn) = runProperName pn
1007− prettyPrintRef (TypeInstanceRef ident) = showIdent ident
1008− prettyPrintRef (ModuleRef name) = "module " ++ runModuleName name
1009− prettyPrintRef (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
1010−
1011− prettyPrintImport :: ModuleName -> ImportDeclarationType -> Maybe ModuleName -> String
1012− prettyPrintImport mn idt qual =
1013− let i = case idt of
1014− Implicit -> runModuleName mn
1015− Explicit refs -> runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")"
1016− Hiding refs -> runModuleName mn ++ " hiding (" ++ intercalate "," (map prettyPrintRef refs) ++ ")"
1017− in i ++ maybe "" (\q -> " as " ++ runModuleName q) qual
1018−
10191050 -- | Simplify an error message
10201051 simplifyErrorMessage :: ErrorMessage -> ErrorMessage
10211052 simplifyErrorMessage (ErrorMessage hints simple) = ErrorMessage (simplifyHints hints) simple
10221053 where
10231054 -- Take the last instance of each "hint category"
10241055 simplifyHints :: [ErrorMessageHint] -> [ErrorMessageHint]
1025− simplifyHints = reverse . nubBy categoriesEqual . reverse
1056+ simplifyHints = reverse . nubBy categoriesEqual . stripRedudantHints simple . reverse
10261057
10271058 -- Don't remove hints in the "other" category
10281059 categoriesEqual :: ErrorMessageHint -> ErrorMessageHint -> Bool
@@ -1032,6 +1063,30 @@ prettyPrintSingleError full level e = flip evalState defaultUnknownMap $ do
10321063 (_, OtherHint) -> False
10331064 (c1, c2) -> c1 == c2
10341065
1066+ -- | See https://github.com/purescript/purescript/issues/1802
1067+ stripRedudantHints :: SimpleErrorMessage -> [ErrorMessageHint] -> [ErrorMessageHint]
1068+ stripRedudantHints CannotApplyFunction{} = stripFirst isApplicationHint
1069+ where
1070+ isApplicationHint ErrorInApplication{} = True
1071+ isApplicationHint _ = False
1072+ stripRedudantHints ExprDoesNotHaveType{} = stripFirst isCheckHint
1073+ where
1074+ isCheckHint ErrorCheckingType{} = True
1075+ isCheckHint _ = False
1076+ stripRedudantHints TypesDoNotUnify{} = stripFirst isUnifyHint
1077+ where
1078+ isUnifyHint ErrorUnifyingTypes{} = True
1079+ isUnifyHint _ = False
1080+ stripRedudantHints _ = id
1081+
1082+ stripFirst :: (ErrorMessageHint -> Bool) -> [ErrorMessageHint] -> [ErrorMessageHint]
1083+ stripFirst p (PositionedError pos : hs) = PositionedError pos : stripFirst p hs
1084+ stripFirst p (ErrorInModule mn : hs) = ErrorInModule mn : stripFirst p hs
1085+ stripFirst p (hint : hs)
1086+ | p hint = hs
1087+ | otherwise = hint : hs
1088+ stripFirst _ [] = []
1089+
10351090 hintCategory :: ErrorMessageHint -> HintCategory
10361091 hintCategory ErrorCheckingType{} = ExprHint
10371092 hintCategory ErrorInferringType{} = ExprHint
@@ -1043,6 +1098,30 @@ prettyPrintSingleError full level e = flip evalState defaultUnknownMap $ do
10431098 hintCategory PositionedError{} = PositionHint
10441099 hintCategory _ = OtherHint
10451100
1101+-- Pretty print and export declaration
1102+prettyPrintExport :: DeclarationRef -> String
1103+prettyPrintExport (TypeRef pn _) = runProperName pn
1104+prettyPrintExport ref = prettyPrintRef ref
1105+
1106+prettyPrintImport :: ModuleName -> ImportDeclarationType -> Maybe ModuleName -> String
1107+prettyPrintImport mn idt qual =
1108+ let i = case idt of
1109+ Implicit -> runModuleName mn
1110+ Explicit refs -> runModuleName mn ++ " (" ++ intercalate ", " (map prettyPrintRef refs) ++ ")"
1111+ Hiding refs -> runModuleName mn ++ " hiding (" ++ intercalate "," (map prettyPrintRef refs) ++ ")"
1112+ in i ++ maybe "" (\q -> " as " ++ runModuleName q) qual
1113+
1114+prettyPrintRef :: DeclarationRef -> String
1115+prettyPrintRef (TypeRef pn Nothing) = runProperName pn ++ "(..)"
1116+prettyPrintRef (TypeRef pn (Just [])) = runProperName pn
1117+prettyPrintRef (TypeRef pn (Just dctors)) = runProperName pn ++ "(" ++ intercalate ", " (map runProperName dctors) ++ ")"
1118+prettyPrintRef (ValueRef ident) = showIdent ident
1119+prettyPrintRef (TypeClassRef pn) = "class " ++ runProperName pn
1120+prettyPrintRef (ProperRef name) = name
1121+prettyPrintRef (TypeInstanceRef ident) = showIdent ident
1122+prettyPrintRef (ModuleRef name) = "module " ++ runModuleName name
1123+prettyPrintRef (PositionedDeclarationRef _ _ ref) = prettyPrintExport ref
1124+
10461125-- |
10471126-- Pretty print multiple errors
10481127--
@@ -1065,12 +1144,12 @@ prettyPrintMultipleErrorsBox full = prettyPrintMultipleErrorsWith Error "Error f
10651144
10661145prettyPrintMultipleErrorsWith :: Level -> String -> String -> Bool -> MultipleErrors -> Box.Box
10671146prettyPrintMultipleErrorsWith level intro _ full (MultipleErrors [e]) =
1068− let result = prettyPrintSingleError full level e
1147+ let result = prettyPrintSingleError full level True e
10691148 in Box.vcat Box.left [ Box.text intro
10701149 , result
10711150 ]
10721151prettyPrintMultipleErrorsWith level _ intro full (MultipleErrors es) =
1073− let result = map (prettyPrintSingleError full level) es
1152+ let result = map (prettyPrintSingleError full level True) es
10741153 in Box.vsep 1 Box.left $ concat $ zipWith withIntro [1 :: Int ..] result
10751154 where
10761155 withIntro i err = [ Box.text (intro ++ " " ++ show i ++ " of " ++ show (length es) ++ ":")
@@ -1133,9 +1212,15 @@ line :: String -> Box.Box
11331212line = Box.text
11341213
11351214renderBox :: Box.Box -> String
1136−renderBox = unlines . map trimEnd . lines . Box.render
1215+renderBox = unlines
1216+ . map (dropWhileEnd isSpace)
1217+ . dropWhile whiteSpace
1218+ . dropWhileEnd whiteSpace
1219+ . lines
1220+ . Box.render
11371221 where
1138− trimEnd = reverse . dropWhile (== ' ') . reverse
1222+ dropWhileEnd p = reverse . dropWhile p . reverse
1223+ whiteSpace = all isSpace
11391224
11401225-- |
11411226-- Rethrow an error with a more detailed error message in the case of failure