-
Notifications
You must be signed in to change notification settings - Fork 152
/
Copy pathComments.hs
143 lines (118 loc) · 5.58 KB
/
Comments.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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
--------------------------------------------------------------------------------
-- | Utilities for assocgating comments with things in a list.
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Language.Haskell.Stylish.Comments
( CommentGroup (..)
, commentGroups
, commentGroupHasComments
, commentGroupSort
) where
--------------------------------------------------------------------------------
import Data.Function (on)
import Data.List (sortBy, sortOn)
import Data.Maybe (isNothing, maybeToList)
import qualified GHC.Hs as GHC
import qualified GHC.Types.SrcLoc as GHC
import qualified GHC.Utils.Outputable as GHC
--------------------------------------------------------------------------------
import Language.Haskell.Stylish.Block
import Language.Haskell.Stylish.GHC
--------------------------------------------------------------------------------
data CommentGroup a = CommentGroup
{ cgBlock :: LineBlock
, cgPrior :: [GHC.LEpaComment]
, cgItems :: [(a, Maybe GHC.LEpaComment)]
, cgFollowing :: [GHC.LEpaComment]
}
--------------------------------------------------------------------------------
instance GHC.Outputable a => Show (CommentGroup a) where
show CommentGroup {..} = "(CommentGroup (" ++
show cgBlock ++ ") (" ++
showOutputable cgPrior ++ ") (" ++
showOutputable cgItems ++ ") (" ++
showOutputable cgFollowing ++ "))"
--------------------------------------------------------------------------------
commentGroups
:: forall a.
(a -> Maybe GHC.RealSrcSpan)
-> [a]
-> [GHC.LEpaComment]
-> [CommentGroup a]
commentGroups getSpan allItems allComments =
work Nothing (sortOn fst allItemsWithLines) (sortOn fst commentsWithLines)
where
allItemsWithLines :: [(LineBlock, a)]
allItemsWithLines = do
item <- allItems
s <- maybeToList $ getSpan item
pure (realSrcSpanToLineBlock s, item)
commentsWithLines :: [(LineBlock, GHC.LEpaComment)]
commentsWithLines = do
comment <- allComments
let s = GHC.anchor $ GHC.getLoc comment
pure (realSrcSpanToLineBlock s, comment)
work
:: Maybe (CommentGroup a)
-> [(LineBlock, a)]
-> [(LineBlock, GHC.LEpaComment)]
-> [CommentGroup a]
work mbCurrent items comments = case takeNext items comments of
Nothing -> maybeToList mbCurrent
Just (b, next, items', comments') ->
let (flush, current) = case mbCurrent of
Just c | adjacent (cgBlock c) b
, nextThingItem next
, following@(_ : _) <- cgFollowing c ->
([c {cgFollowing = []}], CommentGroup b following [] [])
Just c | adjacent (cgBlock c) b ->
([], c {cgBlock = cgBlock c <> b})
_ -> (maybeToList mbCurrent, CommentGroup b [] [] [])
current' = case next of
NextItem i -> current {cgItems = cgItems current <> [(i, Nothing)]}
NextComment c
| null (cgItems current) -> current {cgPrior = cgPrior current <> [c]}
| otherwise -> current {cgFollowing = cgFollowing current <> [c]}
NextItemWithComment i c ->
current {cgItems = cgItems current <> [(i, Just c)]} in
flush ++ work (Just current') items' comments'
--------------------------------------------------------------------------------
takeNext
:: [(LineBlock, a)]
-> [(LineBlock, GHC.LEpaComment)]
-> Maybe (LineBlock, NextThing a, [(LineBlock, a)], [(LineBlock, GHC.LEpaComment)])
takeNext [] [] = Nothing
takeNext [] ((cb, c) : comments) =
Just (cb, NextComment c, [], comments)
takeNext ((ib, i) : items) [] =
Just (ib, NextItem i, items, [])
takeNext ((ib, i) : items) ((cb, c) : comments)
= case blockEnd ib `compare` blockStart cb of
EQ -> Just (ib <> cb, NextItemWithComment i c, items, comments)
LT -> Just (ib, NextItem i, items, (cb, c) : comments)
GT -> Just (cb, NextComment c, (ib, i) : items, comments)
--------------------------------------------------------------------------------
data NextThing a
= NextComment GHC.LEpaComment
| NextItem a
| NextItemWithComment a GHC.LEpaComment
--------------------------------------------------------------------------------
instance GHC.Outputable a => Show (NextThing a) where
show (NextComment c) = "NextComment " ++ showOutputable c
show (NextItem i) = "NextItem " ++ showOutputable i
show (NextItemWithComment i c) =
"NextItemWithComment " ++ showOutputable i ++ " " ++ showOutputable c
--------------------------------------------------------------------------------
nextThingItem :: NextThing a -> Bool
nextThingItem (NextComment _) = False
nextThingItem (NextItem _) = True
nextThingItem (NextItemWithComment _ _) = True
--------------------------------------------------------------------------------
commentGroupHasComments :: CommentGroup a -> Bool
commentGroupHasComments CommentGroup {..} = not $
null cgPrior && all (isNothing . snd) cgItems && null cgFollowing
--------------------------------------------------------------------------------
commentGroupSort :: (a -> a -> Ordering) -> CommentGroup a -> CommentGroup a
commentGroupSort cmp cg = cg
{ cgItems = sortBy (cmp `on` fst) (cgItems cg)
}