1{-# OPTIONS_GHC -Wall #-}
2{-# LANGUAGE OverloadedStrings #-}
3module Reporting.Render.Code
10 , nextLineStartsWithKeyword
15import qualified Data.ByteString as B
16import qualified Data.ByteString.UTF8 as UTF8_BS
17import qualified Data.Char as Char
18import qualified Data.IntSet as IntSet
19import qualified Data.List as List
20import qualified Data.Name as Name
21import qualified Data.Set as Set
22import Data.Word (Word16)
24import qualified Reporting.Annotation as A
25import qualified Reporting.Doc as D
26import Reporting.Doc (Doc)
27import Parse.Primitives (Row, Col)
28import Parse.Symbol (binopCharSet)
29import Parse.Variable (reservedWords)
37 Source [(Word16, String)]
40toSource :: B.ByteString -> Source
43 lines (UTF8_BS.toString source) ++ [""]
50toSnippet :: Source -> A.Region -> Maybe A.Region -> (D.Doc, D.Doc) -> D.Doc
51toSnippet source region highlight (preHint, postHint) =
55 , render source region highlight
60toPair :: Source -> A.Region -> A.Region -> (D.Doc, D.Doc) -> (D.Doc, D.Doc, D.Doc) -> D.Doc
61toPair source r1 r2 (oneStart, oneEnd) (twoStart, twoMiddle, twoEnd) =
62 case renderPair source r1 r2 of
71 TwoChunks code1 code2 ->
87(|>) :: a -> (a -> b) -> b
92render :: Source -> A.Region -> Maybe A.Region -> Doc
93render (Source sourceLines) region@(A.Region (A.Position startLine _) (A.Position endLine _)) maybeSubRegion =
97 |> drop (fromIntegral (startLine - 1))
98 |> take (fromIntegral (1 + endLine - startLine))
101 length (show (fst (last relevantLines)))
104 maybe region id maybeSubRegion
106 case makeUnderline width endLine smallerRegion of
108 drawLines True width smallerRegion relevantLines D.empty
111 drawLines False width smallerRegion relevantLines underline
114makeUnderline :: Int -> Word16 -> A.Region -> Maybe Doc
115makeUnderline width realEndLine (A.Region (A.Position start c1) (A.Position end c2)) =
116 if start /= end || end < realEndLine then
121 spaces = replicate (fromIntegral c1 + width + 1) ' '
122 zigzag = replicate (max 1 (fromIntegral (c2 - c1))) '^'
124 Just (D.fromChars spaces <> D.dullred (D.fromChars zigzag))
127drawLines :: Bool -> Int -> A.Region -> [(Word16, String)] -> Doc -> Doc
128drawLines addZigZag width (A.Region (A.Position startLine _) (A.Position endLine _)) sourceLines finalLine =
130 map (drawLine addZigZag width startLine endLine) sourceLines
134drawLine :: Bool -> Int -> Word16 -> Word16 -> (Word16, String) -> Doc
135drawLine addZigZag width startLine endLine (n, line) =
136 addLineNumber addZigZag width startLine endLine n (D.fromChars line)
139addLineNumber :: Bool -> Int -> Word16 -> Word16 -> Word16 -> Doc -> Doc
140addLineNumber addZigZag width start end n line =
146 replicate (width - length number) ' ' ++ number ++ "|"
149 if addZigZag && start <= n && n <= end then
154 D.fromChars lineNumber <> spacer <> line
166renderPair :: Source -> A.Region -> A.Region -> CodePair
167renderPair source@(Source sourceLines) region1 region2 =
169 (A.Region (A.Position startRow1 startCol1) (A.Position endRow1 endCol1)) = region1
170 (A.Region (A.Position startRow2 startCol2) (A.Position endRow2 endCol2)) = region2
172 if startRow1 == endRow1 && endRow1 == startRow2 && startRow2 == endRow2 then
174 lineNumber = show startRow1
175 spaces1 = replicate (fromIntegral startCol1 + length lineNumber + 1) ' '
176 zigzag1 = replicate (fromIntegral (endCol1 - startCol1)) '^'
177 spaces2 = replicate (fromIntegral (startCol2 - endCol1)) ' '
178 zigzag2 = replicate (fromIntegral (endCol2 - startCol2)) '^'
180 (Just line) = List.lookup startRow1 sourceLines
184 [ D.fromChars lineNumber <> "| " <> D.fromChars line
185 , D.fromChars spaces1 <> D.dullred (D.fromChars zigzag1) <>
186 D.fromChars spaces2 <> D.dullred (D.fromChars zigzag2)
191 (render source region1 Nothing)
192 (render source region2 Nothing)
206whatIsNext :: Source -> Row -> Col -> Next
207whatIsNext (Source sourceLines) row col =
208 case List.lookup row sourceLines of
214 chars = drop (fromIntegral col - 1) line
215 keywords = map Name.toChars (Set.toList reservedWords)
217 case List.find (startsWithKeyword chars) keywords of
227 | isSymbol c -> Operator (c : takeWhile isSymbol cs)
228 | c == ')' -> Close "parenthesis" ')'
229 | c == ']' -> Close "square bracket" ']'
230 | c == '}' -> Close "curly brace" '}'
231 | otherwise -> Other (Just c)
234isSymbol :: Char -> Bool
236 IntSet.member (Char.ord char) binopCharSet
239startsWithKeyword :: [Char] -> [Char] -> Bool
240startsWithKeyword restOfLine keyword =
241 List.isPrefixOf keyword restOfLine
243 case drop (length keyword) restOfLine of
248 not (Char.isAlphaNum c || c == '_')
251nextLineStartsWithKeyword :: [Char] -> Source -> Row -> Maybe (Row, Col)
252nextLineStartsWithKeyword keyword (Source sourceLines) row =
253 case List.lookup (row + 1) sourceLines of
258 if startsWithKeyword (dropWhile (==' ') line) keyword then
259 Just (row + 1, 1 + fromIntegral (length (takeWhile (==' ') line)))
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