lib: followingcomment: parse no comment as "", not "\n"
Same-line & next-line comments of transactions, postings, etc. are now parsed a bit more precisely. Previously parsing no comment gave the same result as an empty comment (a single newline); now it gives an empty string. Also, and perhaps as a consequence of the above, when there's no same-line comment but there is a next-line comment, we'll insert an empty first line, otherwise next-line comments would get moved up to the same line when rendered. Some doctests have been added.
This commit is contained in:
parent
46d6971da7
commit
e88a9c4a5f
@ -122,6 +122,9 @@ import Text.Megaparsec.Custom
|
||||
import Hledger.Data
|
||||
import Hledger.Utils
|
||||
|
||||
-- $setup
|
||||
-- >>> :set -XOverloadedStrings
|
||||
|
||||
-- | A hledger journal reader is a triple of storage format name, a
|
||||
-- detector of that format, and a parser from that format to Journal.
|
||||
data Reader = Reader {
|
||||
@ -977,26 +980,46 @@ emptyorcommentlinep = do
|
||||
-- until the next newline. This parser should extract the "content" from
|
||||
-- comments. The resulting parser returns this content plus the raw text
|
||||
-- of the comment itself.
|
||||
followingcommentp' :: (Monoid a) => TextParser m a -> TextParser m (Text, a)
|
||||
--
|
||||
-- See followingcommentp for tests.
|
||||
--
|
||||
followingcommentp' :: (Monoid a, Show a) => TextParser m a -> TextParser m (Text, a)
|
||||
followingcommentp' contentp = do
|
||||
skipMany spacenonewline
|
||||
sameLine <- try headerp *> match' contentp <|> pure ("", mempty)
|
||||
-- there can be 0 or 1 sameLine
|
||||
sameLine <- try headerp *> ((:[]) <$> match' contentp) <|> pure []
|
||||
_ <- eolof
|
||||
lowerLines <- many $
|
||||
-- there can be 0 or more nextLines
|
||||
nextLines <- many $
|
||||
try (skipSome spacenonewline *> headerp) *> match' contentp <* eolof
|
||||
|
||||
let (textLines, results) = unzip $ sameLine : lowerLines
|
||||
strippedCommentText = T.unlines $ map T.strip textLines
|
||||
result = mconcat results
|
||||
pure (strippedCommentText, result)
|
||||
let
|
||||
-- if there's just a next-line comment, insert an empty same-line comment
|
||||
-- so the next-line comment doesn't get rendered as a same-line comment.
|
||||
sameLine' | null sameLine && not (null nextLines) = [("",mempty)]
|
||||
| otherwise = sameLine
|
||||
(texts, contents) = unzip $ sameLine' ++ nextLines
|
||||
strippedCommentText = T.unlines $ map T.strip texts
|
||||
commentContent = mconcat contents
|
||||
pure (strippedCommentText, commentContent)
|
||||
|
||||
where
|
||||
headerp = char ';' *> skipMany spacenonewline
|
||||
|
||||
{-# INLINABLE followingcommentp' #-}
|
||||
|
||||
-- | Parse the text of a (possibly multiline) comment following a journal
|
||||
-- item.
|
||||
-- | Parse the text of a (possibly multiline) comment following a journal item.
|
||||
--
|
||||
-- >>> rtp followingcommentp "" -- no comment
|
||||
-- Right ""
|
||||
-- >>> rtp followingcommentp ";" -- just a (empty) same-line comment. newline is added
|
||||
-- Right "\n"
|
||||
-- >>> rtp followingcommentp "; \n"
|
||||
-- Right "\n"
|
||||
-- >>> rtp followingcommentp ";\n ;\n" -- a same-line and a next-line comment
|
||||
-- Right "\n\n"
|
||||
-- >>> rtp followingcommentp "\n ;\n" -- just a next-line comment. Insert an empty same-line comment so the next-line comment doesn't become a same-line comment.
|
||||
-- Right "\n\n"
|
||||
--
|
||||
followingcommentp :: TextParser m Text
|
||||
followingcommentp =
|
||||
fst <$> followingcommentp' (void $ takeWhileP Nothing (/= '\n'))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user