diagnose 1.8.1 → 1.8.2
raw patch · 4 files changed
+141/−67 lines, 4 filesdep ~textPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: text
API changes (from Hackage documentation)
Files
- diagnose.cabal +3/−5
- src/Error/Diagnose/Position.hs +2/−3
- src/Error/Diagnose/Report/Internal.hs +89/−58
- test/rendering/Spec.hs +47/−1
diagnose.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: diagnose-version: 1.8.1+version: 1.8.2 synopsis: Beautiful error reporting done easily description: This package provides a simple way of getting beautiful compiler/interpreter errors using a very simple interface for the programmer.@@ -69,7 +69,6 @@ , hashable >=1.3 && <2 , prettyprinter >=1.7.0 && <2 , prettyprinter-ansi-terminal >=1.1.0 && <2- , text >=1.2 && <2 , unordered-containers ==0.2.* , wcwidth >=0.0.1 && <1 if flag(json)@@ -111,7 +110,7 @@ , hashable >=1.3 && <2 , prettyprinter >=1.7.0 && <2 , prettyprinter-ansi-terminal >=1.1.0 && <2- , text >=1.2 && <2+ , text >=1.2 && <3 , unordered-containers ==0.2.* , wcwidth >=0.0.1 && <1 if flag(json)@@ -150,7 +149,7 @@ , hashable >=1.3 && <2 , prettyprinter >=1.7.0 && <2 , prettyprinter-ansi-terminal >=1.1.0 && <2- , text >=1.2 && <2+ , text >=1.2 && <3 , unordered-containers ==0.2.* , wcwidth >=0.0.1 && <1 if flag(json)@@ -188,7 +187,6 @@ , hashable >=1.3 && <2 , prettyprinter >=1.7.0 && <2 , prettyprinter-ansi-terminal >=1.1.0 && <2- , text >=1.2 && <2 , unordered-containers ==0.2.* , wcwidth >=0.0.1 && <1 if flag(json)
src/Error/Diagnose/Position.hs view
@@ -18,7 +18,6 @@ #endif import Data.Default (Default, def) import Data.Hashable (Hashable)-import Data.Text (Text) import GHC.Generics (Generic (..)) import Prettyprinter (Pretty (..), colon) @@ -50,8 +49,8 @@ instance Pretty Position where pretty (Position (bl, bc) (el, ec) f) = pretty f <> at <> pretty bl <> colon <> pretty bc <> dash <> pretty el <> colon <> pretty ec where- at = pretty @Text "@"- dash = pretty @Text "-"+ at = pretty @String "@"+ dash = pretty @String "-" instance Hashable Position
src/Error/Diagnose/Report/Internal.hs view
@@ -252,6 +252,18 @@ in annotate (bold <> color Black) $ mempty <+> pad (leftLen - lineNoLen) ' ' mempty <> pretty lineNo <+> if withUnicode then "│" else "|" {-# INLINE linePrefix #-} +-- | Creates an ellipsis-prefix, when some line numbers are not consecutive.+--+-- Pretty printing yields those results:+--+-- [with unicode] "@␣␣␣␣␣⋮␣@"+-- [without unicode] "@␣␣␣␣...@"+ellipsisPrefix ::+ Int ->+ Bool ->+ Doc AnsiStyle+ellipsisPrefix leftLen withUnicode = pad leftLen ' ' mempty <> annotate (bold <> color Black) (if withUnicode then space <> "⋮" else "...")+ groupMarkersPerFile :: Pretty msg => [(Position, Marker msg)] ->@@ -346,75 +358,94 @@ [(Position, Marker msg)] -> [Int] -> Doc AnsiStyle-prettyAllLines _ _ _ _ _ _ [] [] = mempty-prettyAllLines _ withUnicode isError _ leftLen _ multiline [] =- let colorOfLastMultilineMarker = maybe mempty (markerColor isError . snd) (List.safeLast multiline)- -- take the color of the last multiline marker in case we need to add additional bars+prettyAllLines files withUnicode isError tabSize leftLen inline multiline lineNumbers =+ case lineNumbers of+ [] ->+ showMultiline True multiline+ [l] ->+ let (ms, doc) = showForLine True l+ in doc+ <> prettyAllLines files withUnicode isError tabSize leftLen inline ms []+ l1 : l2 : ls ->+ let (ms, doc) = showForLine False l1+ in doc+ <> (if l2 /= l1 + 1 then hardline <+> dotPrefix leftLen withUnicode else mempty)+ <> prettyAllLines files withUnicode isError tabSize leftLen inline ms (l2 : ls)+ where+ showForLine isLastLine line =+ {-+ A line of code is composed of:+ (1) <line> | <source code>+ (2) : <markers>+ (3) : <marker messages> - prefix = hardline <+> dotPrefix leftLen withUnicode <> space- prefixWithBar color = prefix <> annotate color (if withUnicode then "│ " else "| ")+ Multline markers may also take additional space (2 characters) on the right of the bar+ -}+ let allInlineMarkersInLine = snd =<< filter ((==) line . fst) inline - showMultilineMarkerMessage (_, marker) isLast =- annotate (markerColor isError marker) $- ( if isLast- then if withUnicode then "╰╸ " else "`- "- else if withUnicode then "├╸ " else "|- "- )- <> replaceLinesWith (if isLast then prefix <> " " else prefixWithBar (markerColor isError marker) <> space) (pretty $ markerMessage marker)+ allMultilineMarkersInLine = flip filter multiline \(Position (bl, _) (el, _) _, _) -> bl == line || el == line - showMultilineMarkerMessages [] = []- showMultilineMarkerMessages [m] = [showMultilineMarkerMessage m True]- showMultilineMarkerMessages (m : ms) = showMultilineMarkerMessage m False : showMultilineMarkerMessages ms- in prefixWithBar colorOfLastMultilineMarker <> prefix <> fold (List.intersperse prefix $ showMultilineMarkerMessages $ reverse multiline)-prettyAllLines files withUnicode isError tabSize leftLen inline multiline (line : ls) =- {-- A line of code is composed of:- (1) <line> | <source code>- (2) : <markers>- (3) : <marker messages>+ allMultilineMarkersSpanningLine = flip filter multiline \(Position (bl, _) (el, _) _, _) -> bl < line && el > line - Multline markers may also take additional space (2 characters) on the right of the bar- -}- let allInlineMarkersInLine = snd =<< filter ((==) line . fst) inline+ inSpanOfMultiline = flip any multiline \(Position (bl, _) (el, _) _, _) -> bl <= line && el >= line - allMultilineMarkersInLine = flip filter multiline \(Position (bl, _) (el, _) _, _) -> bl == line || el == line+ colorOfFirstMultilineMarker = maybe id (annotate . markerColor isError . snd) (List.safeHead $ allMultilineMarkersInLine <> allMultilineMarkersSpanningLine)+ -- take the first multiline marker to color the entire line, if there is one - allMultilineMarkersSpanningLine = flip filter multiline \(Position (bl, _) (el, _) _, _) -> bl < line && el > line+ (multilineEndingOnLine, otherMultilines) = flip List.partition multiline \(Position _ (el, _) _, _) -> el == line - inSpanOfMultiline = flip any multiline \(Position (bl, _) (el, _) _, _) -> bl <= line && el >= line+ !additionalPrefix = case allMultilineMarkersInLine of+ [] ->+ if not $ null multiline+ then+ if not $ null allMultilineMarkersSpanningLine+ then colorOfFirstMultilineMarker if withUnicode then "│ " else "| "+ else " "+ else mempty+ (p@(Position _ (el, _) _), marker) : _ ->+ let hasPredecessor = el == line || maybe False ((/=) p . fst . fst) (List.safeUncons multiline)+ in colorOfFirstMultilineMarker+ ( if+ | hasPredecessor && withUnicode -> "├"+ | hasPredecessor -> "|"+ | withUnicode -> "╭"+ | otherwise -> "+"+ )+ <> annotate (markerColor isError marker) (if withUnicode then "┤" else ">")+ <> space - colorOfFirstMultilineMarker = maybe id (annotate . markerColor isError . snd) (List.safeHead $ allMultilineMarkersInLine <> allMultilineMarkersSpanningLine)- -- take the first multiline marker to color the entire line, if there is one+ allMarkersInLine = {- List.sortOn fst $ -} allInlineMarkersInLine <> allMultilineMarkersInLine - !additionalPrefix = case allMultilineMarkersInLine of- [] ->- if not $ null multiline- then- if not $ null allMultilineMarkersSpanningLine- then colorOfFirstMultilineMarker if withUnicode then "│ " else "| "- else " "- else mempty- (p@(Position _ (el, _) _), marker) : _ ->- let hasPredecessor = el == line || maybe False ((/=) p . fst . fst) (List.safeUncons multiline)- in colorOfFirstMultilineMarker- ( if- | hasPredecessor && withUnicode -> "├"- | hasPredecessor -> "|"- | withUnicode -> "╭"- | otherwise -> "+"- )- <> annotate (markerColor isError marker) (if withUnicode then "┤" else ">")- <> space+ (widths, renderedCode) = getLine_ files (allMarkersInLine <> allMultilineMarkersSpanningLine) line tabSize isError+ in ( otherMultilines,+ hardline+ <> {- (1) -} linePrefix leftLen line withUnicode <+> additionalPrefix+ <> renderedCode+ <> {- (2) -} showAllMarkersInLine (not $ null multiline) inSpanOfMultiline colorOfFirstMultilineMarker withUnicode isError leftLen widths allInlineMarkersInLine+ <> showMultiline (isLastLine || List.safeLast multilineEndingOnLine == List.safeLast multiline) multilineEndingOnLine+ ) - allMarkersInLine = {- List.sortOn fst $ -} allInlineMarkersInLine <> allMultilineMarkersInLine+ showMultiline _ [] = mempty+ showMultiline isLastMultiline multiline =+ let colorOfLastMultilineMarker = maybe mempty (markerColor isError . snd) (List.safeLast multiline)+ -- take the color of the last multiline marker in case we need to add additional bars - (widths, renderedCode) = getLine_ files (allMarkersInLine <> allMultilineMarkersSpanningLine) line tabSize isError- in hardline- <> {- (1) -} linePrefix leftLen line withUnicode <+> additionalPrefix- <> renderedCode- <> {- (2) -} showAllMarkersInLine (not $ null multiline) inSpanOfMultiline colorOfFirstMultilineMarker withUnicode isError leftLen widths allInlineMarkersInLine- <> {- (3) -} prettyAllLines files withUnicode isError tabSize leftLen inline multiline ls+ prefix = hardline <+> dotPrefix leftLen withUnicode <> space+ prefixWithBar color = prefix <> annotate color (if withUnicode then "│ " else "| ") + showMultilineMarkerMessage (_, marker) isLast =+ annotate (markerColor isError marker) $+ ( if isLast && isLastMultiline+ then if withUnicode then "╰╸ " else "`- "+ else if withUnicode then "├╸ " else "|- "+ )+ <> replaceLinesWith (if isLast then prefix <> " " else prefixWithBar (markerColor isError marker) <> space) (pretty $ markerMessage marker)++ showMultilineMarkerMessages [] = []+ showMultilineMarkerMessages [m] = [showMultilineMarkerMessage m True]+ showMultilineMarkerMessages (m : ms) = showMultilineMarkerMessage m False : showMultilineMarkerMessages ms+ in prefixWithBar colorOfLastMultilineMarker <> prefix <> fold (List.intersperse prefix $ showMultilineMarkerMessages $ reverse multiline)+ -- | getLine_ :: HashMap FilePath [String] -> [(Position, Marker msg)] -> Int -> Int -> Bool -> (IntMap.HashMap Int Int, Doc AnsiStyle) getLine_ files markers line tabSize isError = case List.safeIndex (line - 1) =<< (HashMap.!?) files . file . fst =<< List.safeHead markers of@@ -430,7 +461,7 @@ \(Position (bl, bc) (el, ec) _, _) -> if bl == el then n >= bc && n < ec- else (bl == line && n >= bc) || (el == line && n < ec)+ else (bl == line && n >= bc) || (el == line && n < ec) || (bl < line && el > line) in maybe id ((\m -> annotate (bold <> markerColor isError m)) . snd) (List.safeHead colorizingMarkers) (pretty c) ) where
test/rendering/Spec.hs view
@@ -31,7 +31,9 @@ ("somefile.zc", "let id<a>(x : a) : a := x\n + 1"), ("err.nst", "\n\n\n\n = jmp g\n\n g: forall(s: Ts, e: Tc).{ %r0: *s64 | s -> e }"), ("unsized.nst", "main: forall(a: Ta, s: Ts, e: Tc).{ %r5: forall().{| s -> e } | s -> %r5 }\n = salloc a\n ; sfree\n"),- ("unicode.txt", "±⅀\t★♲♥🎉汉⑳⓴ჳᏁℳ爪")+ ("unicode.txt", "±⅀\t★♲♥🎉汉⑳⓴ჳᏁℳ爪"),+ ("gaps.txt", "abc\ndef\nghi\njkl\nmno\npqr"),+ ("repro3.file", "\n\n ayo yoa\n a b\n c d e f g\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nlayer qwertyy using yoooo: \"a\" \"b\" \"c\"\n") ] let reports =@@ -64,6 +66,10 @@ errorMultipleFiles, errorWithCode, errorWithStrangeUnicodeInput,+ errorWithMultilineMarkerOn3Lines,+ errorMultilineMarkerNotAtEnd,+ errorWithLineGap,+ repro3, beautifulExample ] @@ -356,5 +362,45 @@ "ⓈⓉⓇⒶⓃⒼⒺ ⓊⓃⒾⒸⓄⒹⒺ" [ (Position (1, 1) (1, 7) "unicode.txt", This "should work fine 🎉"), (Position (1, 7) (1, 9) "unicode.txt", Where "After TAB")+ ]+ []++errorWithMultilineMarkerOn3Lines :: Report String+errorWithMultilineMarkerOn3Lines =+ err+ Nothing+ "Multiline marker on 3 lines"+ [(Position (1, 3) (3, 10) "test.zc", This "should color all 3 lines correctly")]+ []++errorMultilineMarkerNotAtEnd :: Report String+errorMultilineMarkerNotAtEnd =+ err+ Nothing+ "Multiline marker not at end of report"+ [ (Position (1, 10) (2, 3) "test.zc", This "is a multline marker"),+ (Position (3, 5) (3, 13) "test.zc", Where "inline marker found after")+ ]+ []++errorWithLineGap :: Report String+errorWithLineGap =+ err+ Nothing+ "Error with line gaps between two markers"+ [ (Position (1, 1) (1, 3) "gaps.txt", Where "is a first marker"),+ (Position (5, 2) (5, 4) "gaps.txt", This "is the main marker")+ ]+ []++repro3 :: Report String+repro3 =+ err+ (Just "WrongStaticLayerLength")+ "The length of the static layer does not match the length of the template it uses"+ [ (Position (3, 3) (5, 16) "repro3.file", Where "This template has 9 elements"),+ (Position (24, 28) (24, 39) "repro3.file", This "... but this layer only has 3 members"),+ (Position (24, 21) (24, 26) "repro3.file", Where "This is the template being used"),+ (Position (24, 7) (24, 15) "repro3.file", Where "while checking this static layer") ] []