diff --git a/core/src/Text/Interpolation/Nyan/Core.hs b/core/src/Text/Interpolation/Nyan/Core.hs index c580a7d..e7374ce 100644 --- a/core/src/Text/Interpolation/Nyan/Core.hs +++ b/core/src/Text/Interpolation/Nyan/Core.hs @@ -33,6 +33,7 @@ module Text.Interpolation.Nyan.Core , recommendedDefaultSwitchesOptions -- ** Field accessors for default switches options , defSpacesTrimming + , defCommenting , defIndentationStripping , defLeadingNewlineStripping , defTrailingSpacesStripping diff --git a/core/src/Text/Interpolation/Nyan/Core/Internal/Base.hs b/core/src/Text/Interpolation/Nyan/Core/Internal/Base.hs index ecbcde2..a90a7f8 100644 --- a/core/src/Text/Interpolation/Nyan/Core/Internal/Base.hs +++ b/core/src/Text/Interpolation/Nyan/Core/Internal/Base.hs @@ -84,6 +84,7 @@ data PreviewLevel -- | All switches options. data SwitchesOptions = SwitchesOptions { spacesTrimming :: Bool + , commenting :: Bool , indentationStripping :: Bool , leadingNewlineStripping :: Bool , trailingSpacesStripping :: Bool @@ -100,6 +101,7 @@ data SwitchesOptions = SwitchesOptions -- mandatory for specifying in the interpolator. data DefaultSwitchesOptions = DefaultSwitchesOptions { defSpacesTrimming :: Maybe Bool + , defCommenting :: Maybe Bool , defIndentationStripping :: Maybe Bool , defLeadingNewlineStripping :: Maybe Bool , defTrailingSpacesStripping :: Maybe Bool @@ -117,6 +119,7 @@ data DefaultSwitchesOptions = DefaultSwitchesOptions basicDefaultSwitchesOptions :: DefaultSwitchesOptions basicDefaultSwitchesOptions = DefaultSwitchesOptions { defSpacesTrimming = Just False + , defCommenting = Just False , defIndentationStripping = Just False , defLeadingNewlineStripping = Just False , defTrailingSpacesStripping = Just False @@ -130,6 +133,7 @@ basicDefaultSwitchesOptions = DefaultSwitchesOptions recommendedDefaultSwitchesOptions :: DefaultSwitchesOptions recommendedDefaultSwitchesOptions = DefaultSwitchesOptions { defSpacesTrimming = Just False + , defCommenting = Just False , defIndentationStripping = Just True , defLeadingNewlineStripping = Just True , defTrailingSpacesStripping = Just True diff --git a/core/src/Text/Interpolation/Nyan/Core/Internal/Parser.hs b/core/src/Text/Interpolation/Nyan/Core/Internal/Parser.hs index ebd2b9c..c60c4af 100644 --- a/core/src/Text/Interpolation/Nyan/Core/Internal/Parser.hs +++ b/core/src/Text/Interpolation/Nyan/Core/Internal/Parser.hs @@ -16,7 +16,9 @@ import qualified Data.Text as T import Fmt (Builder, build, fmt) import Text.Interpolation.Nyan.Core.Internal.Base import Text.Megaparsec (Parsec, customFailure, eof, errorBundlePretty, label, lookAhead, parse, - single, takeWhile1P, takeWhileP) + single, takeWhile1P, takeWhileP, try) +import Text.Megaparsec.Char (spaceChar) +import Text.Megaparsec.Char.Lexer (skipBlockComment, skipLineComment) import Text.Megaparsec.Error (ShowErrorComponent (..)) newtype OptionChanged = OptionChanged Bool @@ -25,6 +27,7 @@ newtype OptionChanged = OptionChanged Bool -- | An accumulator for switch options during parsing. data SwitchesOptionsBuilder = SwitchesOptionsBuilder { spacesTrimmingB :: (OptionChanged, Maybe Bool) + , commentingB :: (OptionChanged, Maybe Bool) , indentationStrippingB :: (OptionChanged, Maybe Bool) , leadingNewlineStrippingB :: (OptionChanged, Maybe Bool) , trailingSpacesStrippingB :: (OptionChanged, Maybe Bool) @@ -38,6 +41,7 @@ toSwitchesOptionsBuilder :: DefaultSwitchesOptions -> SwitchesOptionsBuilder toSwitchesOptionsBuilder DefaultSwitchesOptions{..} = SwitchesOptionsBuilder { spacesTrimmingB = (OptionChanged False, defSpacesTrimming) + , commentingB = (OptionChanged False, defCommenting) , indentationStrippingB = (OptionChanged False, defIndentationStripping) , leadingNewlineStrippingB = (OptionChanged False, defLeadingNewlineStripping) , trailingSpacesStrippingB = (OptionChanged False, defTrailingSpacesStripping) @@ -50,6 +54,7 @@ toSwitchesOptionsBuilder DefaultSwitchesOptions{..} = finalizeSwitchesOptions :: MonadFail m => SwitchesOptionsBuilder -> m SwitchesOptions finalizeSwitchesOptions SwitchesOptionsBuilder{..} = do spacesTrimming <- fromOptional "spaces trimming" spacesTrimmingB + commenting <- fromOptional "comments handling" commentingB indentationStripping <- fromOptional "indentation stripping" indentationStrippingB leadingNewlineStripping <- fromOptional "leading newline stripping" leadingNewlineStrippingB trailingSpacesStripping <- fromOptional "trailing spaces stripping" trailingSpacesStrippingB @@ -73,6 +78,12 @@ setIfNew desc new (OptionChanged ch, old) | old == Just new = fail $ "Switch option `" <> desc <> "` is set redundantly" | otherwise = return (OptionChanged True, Just new) +setCommenting :: SwitchesOptionsSetter m => Bool -> m () +setCommenting enable = do + opts <- get + res <- setIfNew "comments handling" enable (commentingB opts) + put opts{ commentingB = res } + setSpacesTrimming :: SwitchesOptionsSetter m => Bool -> m () setSpacesTrimming enable = do opts <- get @@ -150,6 +161,11 @@ switchesSectionP defSOpts = , single 'S' $> False ] >>= setSpacesTrimming + , asum + [ single 'c' $> True + , single 'C' $> False + ] >>= setCommenting + , asum [ single 'd' $> True , single 'D' $> False @@ -201,6 +217,7 @@ switchesHelpMessage sopts = (error "") (error "") (error "") + (error "") -- ↑ Note: If you edit this, you may also need to update -- the help messages below. in mconcat @@ -210,6 +227,11 @@ switchesHelpMessage sopts = , ("S", "disable spaces trimming", Just False) ] + , helpOnOptions (defCommenting sopts) + [ ("c", "enable commenting", Just True) + , ("C", "disable commenting", Just False) + ] + , helpOnOptions (defIndentationStripping sopts) [ ("d", "enable indentation stripping", Just True) , ("D", "disable indentation stripping", Just False) @@ -254,11 +276,15 @@ switchesHelpMessage sopts = , val /= defVal ] -intPieceP :: Ord e => Parsec e Text [ParsedIntPiece] -intPieceP = asum - [ +intPieceP :: Ord e => SwitchesOptions -> Parsec e Text [ParsedIntPiece] +intPieceP SwitchesOptions{..} = asum [ + + -- ignore comments if 'commenting' switch is on + guard commenting *> + asum [ skipLineComment "--", skipBlockComment' ] $> [] + -- consume normal text - one . PipString <$> takeWhile1P Nothing (notAnyOf [(== '\\'), (== '#'), isSpace]) + , one . PipString <$> takeWhile1P Nothing (notAnyOf [(== '\\'), (== '#'), isSpace]) -- potentially interpolator case , single '#' *> do @@ -304,6 +330,11 @@ intPieceP = asum ] where + skipBlockComment' = asum + [ skipBlockComment "{-" "-}" + , try $ spaceChar *> skipBlockComment "{-" "-}" + ] + newline = PipNewline . mconcat <$> sequence [ maybe "" T.singleton <$> optional (single '\r') , T.singleton <$> single '\n' @@ -335,7 +366,7 @@ intStringP intStringP sopts = do switches <- switchesSectionP sopts _ <- single '|' - pieces <- glueParsedStrings . concat <$> many intPieceP + pieces <- glueParsedStrings . concat <$> many (intPieceP switches) eof return (switches, pieces) diff --git a/core/tests/Test/Customization.hs b/core/tests/Test/Customization.hs index a9c3970..8a1bd02 100644 --- a/core/tests/Test/Customization.hs +++ b/core/tests/Test/Customization.hs @@ -28,10 +28,12 @@ _AllFieldsAreExported = (error "") (error "") (error "") + (error "") -- ↑ if you change this, also add a field to the record below in basicDefaultSwitchesOptions { defIndentationStripping = Nothing , defSpacesTrimming = Nothing + , defCommenting = Nothing , defLeadingNewlineStripping = Nothing , defTrailingSpacesStripping = Nothing , defReducedNewlines = Nothing diff --git a/core/tests/Test/Interpolator.hs b/core/tests/Test/Interpolator.hs index eaae800..1f89ea8 100644 --- a/core/tests/Test/Interpolator.hs +++ b/core/tests/Test/Interpolator.hs @@ -297,6 +297,45 @@ test_DefaultInterpolator = testGroup "Default interpolator" ] + ---------------------------------- + , testGroup "Commenting" + + [ testCase "Basic comments" do + [int|tc|Abc -- this is a comment|] + @?= "Abc " + + , testCase "Comments in arbitrary lines" do + [int|tc| -- comments at the beginning + My text -- comments in the middle + -- comments at the end + |] @?= " \nMy text \n\n" + + , testCase "Inline block comments" do + [int|tc| My {- inline comment -} text + |] @?= " My text\n" + + , testCase "Multiline block comments" do + [int|tc| My text {- multiline block + comments are fun, + aren't they? + -} + |] @?= " My text\n" + + , testCase "Line comments do not affect the indentation" do + [int|tc| + The beginning + -- some comments in the middle + The end + |] @?= " The beginning\n\n The end\n" + + , testCase "Block comments do not affect the indentation" do + [int|tc| + The beginning {- some clarifying + comments in the middle -} + The end + |] @?= "The beginning\nThe end\n" + ] + ] ] diff --git a/core/tests/Test/Parser.hs b/core/tests/Test/Parser.hs index 98aae69..e6bbcd1 100644 --- a/core/tests/Test/Parser.hs +++ b/core/tests/Test/Parser.hs @@ -121,7 +121,7 @@ test_TextParser = testGroup "Main text parser" basicSwitchesOptions :: SwitchesOptions basicSwitchesOptions = - SwitchesOptions False False False False AnyFromBuilder False False PreviewNone + SwitchesOptions False False False False False AnyFromBuilder False False PreviewNone test_SwitchesParser :: TestTree test_SwitchesParser = testGroup "Switches parser" diff --git a/full/src/Text/Interpolation/Nyan/Tutorial.hs b/full/src/Text/Interpolation/Nyan/Tutorial.hs index 98be387..c775ce6 100644 --- a/full/src/Text/Interpolation/Nyan/Tutorial.hs +++ b/full/src/Text/Interpolation/Nyan/Tutorial.hs @@ -207,6 +207,20 @@ In case monadic actions have side effects, they will be applied in the same orde in which placeholders appear in the quoter. /But you are not going to use this behaviour, don't you?/ +==== c ([c]omments handling) + +Handle line comments starting with @--@ and/or block comments enclosed in @{- ... -}@. + +>>> :{ + [int|c|My text -- this is a line comment|] +:} +"My text " + +>>> :{ + [int|c|My {- this is a block comment -} text|] +:} +"My text" + ==== t (return [t]ext) The quoter will return concrete t'Text'. @@ -272,6 +286,16 @@ affects indentation stripping to also ignore the line with @|]@: :} "\nValue 1 is 5, value 2 is 10\n" +* Comments remain invisible for other switches and thus do not affect them. +Consider the following indentation stripping example: + +>>> :{ + [int|c| + The beginning +-- some comments in the middle + The end|] +:} +"The beginning\n\nThe end" === Customizing the interpolator