on ef280ed help sign in
113 lines 2.8 kB history raw
1{-# OPTIONS_GHC -Wall #-}
2module Reporting.Render.Code
3 ( render
4 )
5 where
7import Control.Applicative ((<|>))
8import Text.PrettyPrint.ANSI.Leijen (Doc, (<>), hardline, dullred, empty, text)
10import qualified Reporting.Region as R
13(|>) :: a -> (a -> b) -> b
14(|>) a f =
15 f a
18(<==>) :: Doc -> Doc -> Doc
19(<==>) a b =
20 a <> hardline <> b
23render :: Maybe R.Region -> R.Region -> String -> Doc
24render maybeSubRegion region@(R.Region start end) source =
25 let
26 (R.Position startLine startColumn) = start
27 (R.Position endLine endColumn) = end
29 relevantLines =
30 lines source
31 |> drop (startLine - 1)
32 |> take (endLine - startLine + 1)
33 in
34 case relevantLines of
35 [] ->
36 empty
38 [sourceLine] ->
39 singleLineRegion startLine sourceLine $
40 case maybeSubRegion of
41 Nothing ->
42 (0, startColumn, endColumn, length sourceLine)
44 Just (R.Region s e) ->
45 (startColumn, R.column s, R.column e, endColumn)
47 firstLine : rest ->
48 let
49 filteredFirstLine =
50 replicate (startColumn - 1) ' '
51 ++ drop (startColumn - 1) firstLine
53 filteredLastLine =
54 take (endColumn) (last rest)
56 focusedRelevantLines =
57 filteredFirstLine : init rest ++ [filteredLastLine]
59 lineNumbersWidth =
60 length (show endLine)
62 subregion =
63 maybeSubRegion <|> Just region
65 numberedLines =
66 zipWith
67 (addLineNumber subregion lineNumbersWidth)
68 [startLine .. endLine]
69 focusedRelevantLines
70 in
71 foldr (<==>) empty numberedLines
74addLineNumber :: Maybe R.Region -> Int -> Int -> String -> Doc
75addLineNumber maybeSubRegion width n line =
76 let
77 number =
78 if n < 0 then " " else show n
80 lineNumber =
81 replicate (width - length number) ' ' ++ number ++ "│"
83 spacer (R.Region start end) =
84 if R.line start <= n && n <= R.line end then
85 dullred (text ">")
86 else
87 text " "
88 in
89 text lineNumber
90 <> maybe (text " ") spacer maybeSubRegion
91 <> text line
94singleLineRegion :: Int -> String -> (Int, Int, Int, Int) -> Doc
95singleLineRegion lineNum sourceLine (start, innerStart, innerEnd, end) =
96 let
97 width =
98 length (show lineNum)
100 underline =
101 text (replicate (innerStart + width + 1) ' ')
102 <>
103 dullred (text (replicate (max 1 (innerEnd - innerStart)) '^'))
105 trimmedSourceLine =
106 sourceLine
107 |> drop (start - 1)
108 |> take (end - start + 1)
109 |> (++) (replicate (start - 1) ' ')
110 in
111 addLineNumber Nothing width lineNum trimmedSourceLine
112 <==>
113 underline