1{-# LANGUAGE BangPatterns #-}
2{-# LANGUAGE DeriveDataTypeable #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE TupleSections #-}
7-- | Functions for working with comment stream.
9module Ormolu.Parser.CommentStream
18import Data.Char (isSpace)
19import Data.Data (Data)
20import Data.Either (partitionEithers)
21import Data.List (isPrefixOf, sortOn, dropWhileEnd)
22import Data.List.NonEmpty (NonEmpty (..))
23import Data.Maybe (mapMaybe)
24import Ormolu.Parser.Pragma
25import Ormolu.Utils (showOutputable)
27import qualified Data.List.NonEmpty as NE
29import qualified Lexer as GHC
31-- | A stream of 'RealLocated' 'Comment's in ascending order with respect to
32-- beginning of corresponding spans.
34newtype CommentStream = CommentStream [RealLocated Comment]
35 deriving (Eq, Data, Semigroup, Monoid)
37-- | A wrapper for a single comment. The 'NonEmpty' list inside contains
38-- lines of multiline comment @{- … -}@ or just single item\/line otherwise.
40newtype Comment = Comment (NonEmpty String)
41 deriving (Eq, Show, Data)
43-- | Create 'CommentStream' from 'GHC.PState'. We also create a 'Set' of
44-- extensions here, which is not sorted in any way. The pragma comment are
45-- removed from the 'CommentStream'.
48 :: [Located String] -- ^ Extra comments to include
49 -> GHC.PState -- ^ Parser state to use for comment extraction
50 -> (CommentStream, [Pragma])
51 -- ^ Comment stream and a set of extracted pragmas
52mkCommentStream extraComments pstate =
54 -- NOTE It's easier to normalize pragmas right when we construct comment
55 -- streams. Because this way we need to do it only once and when we
56 -- perform checking later they'll automatically match.
57 mkComment <$> sortOn (realSrcSpanStart . getLoc) comments
61 (comments, pragmas) = partitionEithers (partitionComments <$> rawComments)
62 rawComments = mapMaybe toRealSpan $
64 (fmap unAnnotationComment <$> GHC.comment_q pstate) ++
65 concatMap (fmap (fmap unAnnotationComment) . snd)
66 (GHC.annotations_comments pstate)
68-- | Test whether a 'Comment' looks like a Haddock following a definition,
69-- i.e. something starting with @-- ^@.
71isPrevHaddock :: Comment -> Bool
72isPrevHaddock (Comment (x :| _)) = "-- ^" `isPrefixOf` x
74-- | Pretty-print a 'CommentStream'.
76showCommentStream :: CommentStream -> String
77showCommentStream (CommentStream xs) = unlines $
80 showComment (GHC.L l str) = showOutputable l ++ " " ++ show str
82----------------------------------------------------------------------------
85-- | Normalize comment string. Sometimes one multi-line comment is turned
86-- into several lines for subsequent outputting with correct indentation for
89mkComment :: RealLocated String -> RealLocated Comment
90mkComment (L l s) = L l . Comment . fmap dropTrailing $
91 if "{-" `isPrefixOf` s
92 then case NE.nonEmpty (lines s) of
98 else length (takeWhile isSpace y)
99 n = minimum (startIndent : fmap getIndent xs)
100 in x :| (drop n <$> xs)
103 dropTrailing = dropWhileEnd isSpace
104 startIndent = srcSpanStartCol l - 1
106-- | Get a 'String' from 'GHC.AnnotationComment'.
108unAnnotationComment :: GHC.AnnotationComment -> String
109unAnnotationComment = \case
110 GHC.AnnDocCommentNext s -> s
111 GHC.AnnDocCommentPrev s -> s
112 GHC.AnnDocCommentNamed s -> s
113 GHC.AnnDocSection _ s -> s
114 GHC.AnnDocOptions s -> s
115 GHC.AnnLineComment s -> s
116 GHC.AnnBlockComment s -> s
118toRealSpan :: Located a -> Maybe (RealLocated a)
119toRealSpan (L (RealSrcSpan l) a) = Just (L l a)
120toRealSpan _ = Nothing
122-- | If a given comment is a pragma, return it in parsed form in 'Right'.
123-- Otherwise return the original comment unchanged.
126 :: RealLocated String
127 -> Either (RealLocated String) Pragma
128partitionComments input =
129 case parsePragma (unLoc input) of
130 Nothing -> Left input
131 Just pragma -> Right pragma
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