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)
25import Ormolu.Parser.LanguagePragma
26import Ormolu.Utils (showOutputable)
28import qualified Data.List.NonEmpty as NE
29import qualified Data.Set as S
31import qualified Lexer as GHC
33-- | A stream of 'RealLocated' 'Comment's in ascending order with respect to
34-- beginning of corresponding spans.
36newtype CommentStream = CommentStream [RealLocated Comment]
37 deriving (Eq, Data, Semigroup, Monoid)
39-- | A wrapper for a single comment. The 'NonEmpty' list inside contains
40-- lines of multiline comment @{- … -}@ or just single item\/line otherwise.
42newtype Comment = Comment (NonEmpty String)
43 deriving (Eq, Show, Data)
45-- | Create 'CommentStream' from 'GHC.PState'. We also create a 'Set' of
46-- extensions here, which is not sorted in any way. The pragma comment are
47-- removed from the 'CommentStream'.
50 :: [Located String] -- ^ Extra comments to include
51 -> GHC.PState -- ^ Parser state to use for comment extraction
52 -> (CommentStream, Set String)
53 -- ^ Comment stream and a set of extensions enabled
54mkCommentStream extraComments pstate =
56 -- NOTE It's easier to normalize pragmas right when we construct comment
57 -- streams. Because this way we need to do it only once and when we
58 -- perform checking later they'll automatically match.
59 mkComment <$> sortOn (realSrcSpanStart . getLoc) comments
63 (comments, exts) = partitionEithers (partitionComments <$> rawComments)
64 rawComments = mapMaybe toRealSpan $
66 (fmap unAnnotationComment <$> GHC.comment_q pstate) ++
67 concatMap (fmap (fmap unAnnotationComment) . snd)
68 (GHC.annotations_comments pstate)
70-- | Test whether a 'Comment' looks like a Haddock following a definition,
71-- i.e. something starting with @-- ^@.
73isPrevHaddock :: Comment -> Bool
74isPrevHaddock (Comment (x :| _)) = "-- ^" `isPrefixOf` x
76-- | Pretty-print a 'CommentStream'.
78showCommentStream :: CommentStream -> String
79showCommentStream (CommentStream xs) = unlines $
82 showComment (GHC.L l str) = showOutputable l ++ " " ++ show str
84----------------------------------------------------------------------------
87-- | Normalize comment string. Sometimes one multi-line comment is turned
88-- into several lines for subsequent outputting with correct indentation for
91mkComment :: RealLocated String -> RealLocated Comment
92mkComment (L l s) = L l . Comment . fmap dropTrailing $
93 if "{-" `isPrefixOf` s
94 then case NE.nonEmpty (lines s) of
100 else length (takeWhile isSpace y)
101 n = minimum (startIndent : fmap getIndent xs)
102 in x :| (drop n <$> xs)
105 dropTrailing = dropWhileEnd isSpace
106 startIndent = srcSpanStartCol l - 1
108-- | Get a 'String' from 'GHC.AnnotationComment'.
110unAnnotationComment :: GHC.AnnotationComment -> String
111unAnnotationComment = \case
112 GHC.AnnDocCommentNext s -> s
113 GHC.AnnDocCommentPrev s -> s
114 GHC.AnnDocCommentNamed s -> s
115 GHC.AnnDocSection _ s -> s
116 GHC.AnnDocOptions s -> s
117 GHC.AnnLineComment s -> s
118 GHC.AnnBlockComment s -> s
120toRealSpan :: Located a -> Maybe (RealLocated a)
121toRealSpan (L (RealSrcSpan l) a) = Just (L l a)
122toRealSpan _ = Nothing
124-- | If a given comment is a LANGUAGE pragma, return the set of extensions
125-- it enables in 'Right'. Otherwise return the original comment unchanged.
128 :: RealLocated String
129 -> Either (RealLocated String) (Set String)
130partitionComments input =
131 case parseLanguagePragma (unLoc input) of
132 Nothing -> Left input
133 Just exts -> Right exts
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