aboutsummaryrefslogtreecommitdiffstats
path: root/app/History/Scramble.hs
blob: 017523a5a5aa80cc4c1ea6e1d0dd4968767c97f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
module History.Scramble
  ( Scramble (..),
    getScrambleOf,
    getIssuesOfFile,
    fromComment,
  )
where

import Backend qualified
import CMark qualified as D
import Comment qualified as G
import Control.Exception (Handler (..), catches)
import Data.Binary (Binary)
import Data.Digest.Pure.SHA qualified as S
import Data.Map qualified as M
import Data.Maybe (catMaybes)
import Data.Text qualified as T
import Data.Text.Lazy qualified as LT
import Data.Text.Lazy.Encoding qualified as LT
import Exception qualified as E
import GHC.Generics (Generic)
import Issue qualified as I
import Issue.Parser qualified as I
import Issue.Tag qualified as I
import Issue.Text qualified as I
import Parallel (parMapM)
import Render qualified as P

-- | `Scramble` records the complete issues ONLY in files that have
-- been changed in the commit.
data Scramble = Scramble
  { commitHash :: Backend.CommitHash,
    filesChanged :: [FilePath],
    issues :: M.Map T.Text I.Issue
  }
  deriving (Show, Binary, Generic)

getScrambleOf :: Backend.CommitHash -> IO Scramble
getScrambleOf commitHash = do
  filesChanged <- Backend.getChangedFilesOf commitHash
  issues <- concat <$> mapM (getIssuesOfFile commitHash) filesChanged
  pure $
    Scramble
      { issues =
          M.unions
            [ M.singleton issue.id issue | issue <- issues
            ],
        ..
      }

-- | Get all issues in the given directory and file.
getIssuesOfFile :: Backend.CommitHash -> FilePath -> IO [I.Issue]
getIssuesOfFile commitHash filename =
  ( fmap catMaybes . parMapM (fromComment commitHash)
      =<< G.getComments commitHash filename
  )
    `catches` [ Handler \(_ :: E.UnknownFile) -> pure [],
                Handler \(_ :: E.UnsupportedLanguage) -> pure []
              ]

-- | Note that `provenance` is trivial and needs to be fixed up later.
fromComment :: Backend.CommitHash -> G.Comment -> IO (Maybe I.Issue)
fromComment commitHash comment = do
  commit <- Backend.getCommitOf commitHash
  let provenance = I.Provenance commit commit

  pure $
    ( \parseResult ->
        let (markers, title) =
              I.stripIssueMarkers (T.pack (show (P.render parseResult.heading)))
         in I.Issue
              { commitHash = commitHash,
                language = comment.language,
                rawTextHash = S.sha1 (LT.encodeUtf8 (LT.fromStrict rawText)),
                title = title,
                file = comment.filePath,
                provenance = provenance,
                startByte = comment.startByte,
                endByte = comment.endByte,
                startPoint = comment.startPoint,
                endPoint = comment.endPoint,
                tags = I.extractTags parseResult.tags,
                markers = markers,
                commentStyle = commentStyle,
                closed = False
              }
    )
      <$> I.parse I.issueMarkers (D.commonmarkToNode [] rawText)
  where
    (commentStyle, rawText) = G.uncomment comment.language comment.text