on master help sign in
Implement diffing of comment annotations
commitbf22720b6190cc97cf8d5831a99f45c3cd627c51 authormrkkrp <mark.karpov@tweag.io> dateThu 21 Feb 2019, 21:50 (8 years ago) parent41a54ca
4 files changed+68−24
ormolu.cabal+1 src/Ormolu/Comments.hs+33 src/Ormolu/Diff.hs+30−4 src/Ormolu/Printer/Comments.hs+4−20
ormolu.cabal+1
@@ -37,6 +37,7 @@ library
3737 , syb >= 0.7 && < 0.8
3838 , text >= 0.2 && < 1.3
3939 exposed-modules: Ormolu
40+ , Ormolu.Comments
4041 , Ormolu.Config
4142 , Ormolu.Diff
4243 , Ormolu.Parser
src/Ormolu/Comments.hsnew file+33
@@ -0,0 +1,33 @@
1+-- | Various functions for manipulation of 'Comment's.
2+
3+module Ormolu.Comments
4+ ( annComment
5+ , normalizeComment
6+ )
7+where
8+
9+import Data.List (isPrefixOf)
10+import Language.Haskell.GHC.ExactPrint.Types
11+
12+-- | If 'KeywordId' is a comment, extract it.
13+
14+annComment :: KeywordId -> Maybe Comment
15+annComment (AnnComment x) = Just x
16+annComment _ = Nothing
17+
18+-- | Normalize comment string. Sometimes one multi-line comment is turned
19+-- into several lines for subsequent outputting with correct indentation for
20+-- each line.
21+
22+normalizeComment :: String -> [String]
23+normalizeComment s =
24+ if isMultiline s
25+ then if isPragma s
26+ then [normalizePragma s]
27+ else normalizeIndent s
28+ else [s]
29+ where
30+ isMultiline x = not ("--" `isPrefixOf` x)
31+ isPragma x = "{-#" `isPrefixOf` x
32+ normalizeIndent = fmap (dropWhile (== ' ')) . lines
33+ normalizePragma = unwords . words
src/Ormolu/Diff.hs+30−4
@@ -1,5 +1,6 @@
11{-# LANGUAGE DeriveDataTypeable #-}
22{-# LANGUAGE RankNTypes #-}
3+{-# LANGUAGE RecordWildCards #-}
34
45-- | Diffing GHC ASTs modulo span positions.
56
@@ -9,8 +10,11 @@ module Ormolu.Diff
910where
1011
1112import Data.Generics
13+import Data.Maybe (mapMaybe)
1214import GHC
1315import Language.Haskell.GHC.ExactPrint.Types
16+import Ormolu.Comments
17+import qualified Data.Map.Strict as M
1418
1519-- | Return 'False' of two annotated ASTs are the same modulo span
1620-- positions.
@@ -19,17 +23,39 @@ diff
1923 :: (Anns, ParsedSource) -- ^ First annotated AST
2024 -> (Anns, ParsedSource) -- ^ Second annotated AST
2125 -> Bool
22−diff (_, ps0) (_, ps1) =
23− not (matchParsedSources ps0 ps1)
26+diff (anns0, ps0) (anns1, ps1) =
27+ not (matchIgnoringSrcSpans (simplifyAnns anns0) (simplifyAnns anns1))
28+ || not (matchIgnoringSrcSpans ps0 ps1)
2429
2530-- | Compare two 'ParsedSource' values disregarding differences in
2631-- 'SrcSpan's.
2732
28−matchParsedSources :: ParsedSource -> ParsedSource -> Bool
29−matchParsedSources x0 y0 = geq' x0 y0
33+matchIgnoringSrcSpans :: Data a => a -> a -> Bool
34+matchIgnoringSrcSpans x0 y0 = geq' x0 y0
3035 where
3136 geq' :: GenericQ (GenericQ Bool)
3237 geq' x y = (toConstr x == toConstr y)
3338 && and (gzipWithQ (geq' `extQ` srcSpanEq) x y)
3439 srcSpanEq :: SrcSpan -> GenericQ Bool
3540 srcSpanEq _ _ = True
41+
42+-- | Simplified collection of 'Comment's.
43+
44+data Comments = Comments [Comment] [Comment] [Comment]
45+ deriving (Show, Typeable, Data)
46+
47+-- | Simplify a collection of annotations.
48+
49+simplifyAnns :: Anns -> [Comments]
50+simplifyAnns = fmap simplifyAnn . M.elems
51+
52+-- | Simplify single annotation.
53+
54+simplifyAnn :: Annotation -> Comments
55+simplifyAnn Ann {..} = Comments
56+ (f . fst <$> annPriorComments)
57+ (f . fst <$> annFollowingComments)
58+ (mapMaybe (fmap f . annComment) (fst <$> annsDP))
59+ where
60+ f (Comment str i o) =
61+ Comment (unlines $ normalizeComment str) i o
src/Ormolu/Printer/Comments.hs+4−20
@@ -19,9 +19,9 @@ where
1919import ApiAnnotation (AnnKeywordId (AnnModule))
2020import Control.Monad
2121import Data.Bifunctor
22−import Data.List (isPrefixOf)
2322import Data.Maybe (mapMaybe)
2423import Language.Haskell.GHC.ExactPrint.Types
24+import Ormolu.Comments
2525import Ormolu.Printer.Internal
2626import SrcLoc
2727import qualified Data.Text as T
@@ -71,19 +71,9 @@ spitComments = mapM_ $ \(comment, (Decoration d0 d1)) -> do
7171
7272spitComment :: Comment -> R ()
7373spitComment (Comment str _ _) =
74− if isMultiline str
75− then if isPragma str
76− then handleOne (normalizePragma str)
77− else forM_ (normalizeIndent str) handleOne
78− else handleOne str
79− where
80− handleOne x = do
81− ensureIndent
82− spit (T.pack x)
83− isMultiline x = not ("--" `isPrefixOf` x)
84− isPragma x = "{-#" `isPrefixOf` x
85− normalizeIndent = fmap (dropWhile (== ' ')) . lines
86− normalizePragma = unwords . words
74+ forM_ (normalizeComment str) $ \x -> do
75+ ensureIndent
76+ spit (T.pack x)
8777
8878-- | Partition annotations to get a collection of 'Comment's preceding a
8979-- definition and following it. Every 'Comment' has corresponding
@@ -144,12 +134,6 @@ fixupLastDec [] = []
144134fixupLastDec [(c, Decoration d0 _)] = [(c, Decoration d0 NoDec)]
145135fixupLastDec (c:cs) = c : fixupLastDec cs
146136
147−-- | If 'KeywordId' is a comment, extract it.
148−
149−annComment :: KeywordId -> Maybe Comment
150−annComment (AnnComment x) = Just x
151−annComment _ = Nothing
152−
153137-- | Replace 'DeltaPos' with 'Decoration'.
154138
155139addDecoration