diff --git a/CHANGELOG.md b/CHANGELOG.md index 24de54a03..479971dcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,8 @@ * Fix an inconsistency in formatting of types in GADT declarations in certain cases. [PR 932](https://github.com/tweag/ormolu/pull/932). +* Fix comment in empty export list being moved out [Issue 906](https://github.com/tweag/ormolu/issues/906) + ## Ormolu 0.5.0.1 * Fixed a bug in the diff printing functionality. [Issue diff --git a/data/examples/module-header/multiline-empty-comment-out.hs b/data/examples/module-header/multiline-empty-comment-out.hs new file mode 100644 index 000000000..83579f6e5 --- /dev/null +++ b/data/examples/module-header/multiline-empty-comment-out.hs @@ -0,0 +1,4 @@ +module Foo + ( -- test + ) +where diff --git a/data/examples/module-header/multiline-empty-comment.hs b/data/examples/module-header/multiline-empty-comment.hs new file mode 100644 index 000000000..fa29986a1 --- /dev/null +++ b/data/examples/module-header/multiline-empty-comment.hs @@ -0,0 +1,2 @@ +module Foo ( -- test + ) where diff --git a/src/Ormolu/Printer/Combinators.hs b/src/Ormolu/Printer/Combinators.hs index 50bb8deca..5ba592243 100644 --- a/src/Ormolu/Printer/Combinators.hs +++ b/src/Ormolu/Printer/Combinators.hs @@ -108,7 +108,7 @@ located :: located (L l' a) f = case loc' l' of UnhelpfulSpan _ -> f a RealSrcSpan l _ -> do - spitPrecedingComments l + spitPrecedingComments True l withEnclosingSpan l $ switchLayout [RealSrcSpan l Nothing] (f a) spitFollowingComments l diff --git a/src/Ormolu/Printer/Comments.hs b/src/Ormolu/Printer/Comments.hs index 92c578bec..870c738a4 100644 --- a/src/Ormolu/Printer/Comments.hs +++ b/src/Ormolu/Printer/Comments.hs @@ -25,16 +25,23 @@ import Ormolu.Printer.Internal -- | Output all preceding comments for an element at given location. spitPrecedingComments :: + -- | Whether to output a newline after the last comment + Bool -> -- | Span of the element to attach comments to RealSrcSpan -> R () -spitPrecedingComments ref = do +spitPrecedingComments newlineAfter ref = do comments <- handleCommentSeries (spitPrecedingComment ref) - when (not $ null comments) $ do + + whenNonEmpty comments $ \(lastComment NE.:| _) -> do + when newlineAfter $ if theSameLinePre (getLoc lastComment) ref then space else newline + lastMark <- getSpanMark -- Insert a blank line between the preceding comments and the thing -- after them if there was a blank line in the input. when (needsNewlineBefore ref lastMark) newline + where + whenNonEmpty xs f = maybe (return ()) f (NE.nonEmpty xs) -- | Output all comments following an element at given location. spitFollowingComments :: @@ -43,7 +50,7 @@ spitFollowingComments :: R () spitFollowingComments ref = do trimSpanStream ref - void $ handleCommentSeries (spitFollowingComment ref) + void $ handleCommentSeries (\_ -> spitFollowingComment ref) -- | Output all remaining comments in the comment stream. spitRemainingComments :: R () @@ -51,7 +58,7 @@ spitRemainingComments = do -- Make sure we have a blank a line between the last definition and the -- trailing comments. newline - void $ handleCommentSeries spitRemainingComment + void $ handleCommentSeries (\_ -> spitRemainingComment) ---------------------------------------------------------------------------- -- Single-comment functions @@ -60,12 +67,18 @@ spitRemainingComments = do spitPrecedingComment :: -- | Span of the element to attach comments to RealSrcSpan -> + -- | The last comment output, if any + Maybe LComment -> -- | The comment that was output, if any R (Maybe LComment) -spitPrecedingComment ref = do +spitPrecedingComment ref mLastComment = do mlastMark <- getSpanMark let p (L l _) = realSrcSpanEnd l <= realSrcSpanStart ref withPoppedComment p $ \l comment -> do + case mLastComment of + Just lastComment -> if theSameLinePre (getLoc lastComment) ref then space else newline + Nothing -> return () + lineSpans <- thisLineSpans let thisCommentLine = srcLocLine (realSrcSpanStart l) needsNewline = @@ -74,9 +87,6 @@ spitPrecedingComment ref = do Just spn -> srcLocLine (realSrcSpanEnd spn) /= thisCommentLine when (needsNewline || needsNewlineBefore l mlastMark) newline spitCommentNow l comment - if theSameLinePre l ref - then space - else newline -- | Output a comment that follows element at given location immediately on -- the same line, if there is any. @@ -118,17 +128,17 @@ spitRemainingComment = do -- | Output series of comments. handleCommentSeries :: - -- | Output and return the next comment, if any - R (Maybe LComment) -> + -- | Given the last output comment, output and return the next comment, if any + (Maybe LComment -> R (Maybe LComment)) -> -- | The comments outputted R [LComment] -handleCommentSeries f = go +handleCommentSeries f = go Nothing where - go = do - mComment <- f + go lastComment = do + mComment <- f lastComment case mComment of Nothing -> return [] - Just comment -> (comment:) <$> go + Just comment -> (comment:) <$> go (Just comment) -- | Try to pop a comment using given predicate and if there is a comment -- matching the predicate, print it out. diff --git a/src/Ormolu/Printer/Meat/ImportExport.hs b/src/Ormolu/Printer/Meat/ImportExport.hs index fb709e607..b31d94488 100644 --- a/src/Ormolu/Printer/Meat/ImportExport.hs +++ b/src/Ormolu/Printer/Meat/ImportExport.hs @@ -15,6 +15,7 @@ import GHC.LanguageExtensions.Type import GHC.Types.SrcLoc import GHC.Unit.Types import Ormolu.Printer.Combinators +import Ormolu.Printer.Comments (spitPrecedingComments) import Ormolu.Printer.Meat.Common import Ormolu.Utils (RelativePos (..), attachRelativePos) @@ -28,6 +29,13 @@ p_hsmodExports lexports = (\(p, l) -> sitcc (located l (p_lie layout p))) (attachRelativePos exports) + -- if there are any more comments before the close parens, + -- output them now + case al_close . anns . ann . getLoc $ lexports of + Nothing -> return () + Just (AddEpAnn _ closeParenLoc) -> do + spitPrecedingComments False $ epaLocationRealSrcSpan closeParenLoc + p_hsmodImport :: ImportDecl GhcPs -> R () p_hsmodImport ImportDecl {..} = do useQualifiedPost <- isExtensionEnabled ImportQualifiedPost