forked from lep/jassdoc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Annotation.hs
67 lines (53 loc) · 2.42 KB
/
Annotation.hs
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
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Annotation (Annotations(..), parseDocstring) where
import qualified Data.ByteString.Lazy.Char8 as L8
import Control.Arrow (second, Arrow ((***)))
import Data.Bifunctor (bimap)
import Data.Aeson (ToJSON (toJSON))
import Data.Text.Encoding (decodeUtf8Lenient)
import Data.ByteString.Lazy.Char8 (toStrict)
type Accumulator = ([L8.ByteString], [(L8.ByteString, [L8.ByteString])])
newtype Annotations = Annotations { getAnnotations :: [(L8.ByteString, L8.ByteString)] }
deriving (Semigroup, Monoid)
instance ToJSON Annotations where
toJSON (Annotations as) = toJSON $ map (x *** x) $ filter (not.L8.null.snd) as
where
x = decodeUtf8Lenient . toStrict
parseDocstring :: L8.ByteString -> Annotations
parseDocstring x =
let (comment, annotations) = parseDocstring' x
in Annotations $ ("comment", comment):annotations
parseDocstring' :: L8.ByteString
-> (L8.ByteString, [(L8.ByteString, L8.ByteString)])
parseDocstring' = bimap (trimWhitespace . myUnlines . reverse)
(map (second $ myUnlines . reverse ) )
. flip go mempty
. L8.lines
where
go :: [L8.ByteString] -> Accumulator -> Accumulator
-- we reverse the annotations to have it inserted in the db in the same
-- order they are written in the file. that way we can use sqlites _rowid_
-- to query the annotations in the same order as they were written.
-- this *might* only work for fresh builds as i don't know if sqlite
-- recycles their internal rowids.
go [] acc = second reverse acc
go (x:xs) (descr, annotations)
| Just ann <- getAnn x = go xs (descr, ann:annotations)
| null annotations = go xs (x:descr, annotations)
| otherwise =
let (anTag, anLines):as = annotations
in go xs (descr, (anTag, x:anLines):as)
getAnn line =
let words = map L8.unpack $ L8.words line
in case words of
('@':ann):text -> Just (L8.pack ann, [trimWhitespace . L8.pack $ unwords text])
_ -> Nothing
trimWhitespace :: L8.ByteString -> L8.ByteString
trimWhitespace =
{- L8.reverse
. L8.dropWhile (\x -> x=='\r' || x == '\n') -- drop back newline
. L8.reverse
. -} L8.dropWhile (\x -> x=='\r' || x == '\n') -- drop front newline
myUnlines :: [L8.ByteString] -> L8.ByteString
myUnlines = L8.intercalate "\n"