PyF 0.10.0.1 → 0.10.1.0
raw patch · 13 files changed
+139/−91 lines, 13 filesPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- PyF.Class: pyfFormatFractional :: PyfFormatFractional a => Format t t' 'Fractional -> SignMode -> Maybe (Int, AlignMode k, Char) -> Maybe (Int, Char) -> Maybe Int -> a -> String
+ PyF.Class: pyfFormatFractional :: (PyfFormatFractional a, Integral paddingWidth, Integral precision) => Format t t' 'Fractional -> SignMode -> Maybe (paddingWidth, AlignMode k, Char) -> Maybe (Int, Char) -> Maybe precision -> a -> String
- PyF.Class: pyfFormatIntegral :: PyfFormatIntegral i => Format t t' 'Integral -> SignMode -> Maybe (Int, AlignMode k, Char) -> Maybe (Int, Char) -> i -> String
+ PyF.Class: pyfFormatIntegral :: (PyfFormatIntegral i, Integral paddingWidth) => Format t t' 'Integral -> SignMode -> Maybe (paddingWidth, AlignMode k, Char) -> Maybe (Int, Char) -> i -> String
- PyF.Formatters: formatFractional :: RealFloat f => Format t t' 'Fractional -> SignMode -> Maybe (Int, AlignMode k, Char) -> Maybe (Int, Char) -> Maybe Int -> f -> String
+ PyF.Formatters: formatFractional :: (RealFloat f, Integral paddingWidth, Integral precision) => Format t t' 'Fractional -> SignMode -> Maybe (paddingWidth, AlignMode k, Char) -> Maybe (Int, Char) -> Maybe precision -> f -> String
- PyF.Formatters: formatIntegral :: Integral i => Format t t' 'Integral -> SignMode -> Maybe (Int, AlignMode k, Char) -> Maybe (Int, Char) -> i -> String
+ PyF.Formatters: formatIntegral :: Integral paddingWidth => Integral i => Format t t' 'Integral -> SignMode -> Maybe (paddingWidth, AlignMode k, Char) -> Maybe (Int, Char) -> i -> String
- PyF.Internal.PythonSyntax: Padding :: Integer -> Maybe (Maybe Char, AnyAlign) -> Padding
+ PyF.Internal.PythonSyntax: Padding :: ExprOrValue Int -> Maybe (Maybe Char, AnyAlign) -> Padding
- PyF.Internal.PythonSyntax: Precision :: ExprOrValue Integer -> Precision
+ PyF.Internal.PythonSyntax: Precision :: ExprOrValue Int -> Precision
Files
- ChangeLog.md +8/−0
- PyF.cabal +1/−1
- Readme.md +14/−13
- src/PyF/Class.hs +5/−3
- src/PyF/Formatters.hs +10/−9
- src/PyF/Internal/Meta.hs +14/−6
- src/PyF/Internal/Parser.hs +1/−0
- src/PyF/Internal/ParserEx.hs +7/−5
- src/PyF/Internal/PythonSyntax.hs +17/−8
- src/PyF/Internal/QQ.hs +28/−28
- test/Spec.hs +28/−13
- test/SpecUtils.hs +3/−2
- test/golden/{helloCOLON=100}.golden +3/−3
ChangeLog.md view
@@ -1,5 +1,13 @@ # Revision history for PyF +## 0.10.1.0 -- 2021-12-05++- Padding width can now be any arbitrary Haskell expression, such as `[fmt|hello pi = {pi:<{5 * 10}}|]`.+- Precision (and now padding width) arbitrary expression can now be any `Integral` and it is not limited to `Int` anymore.+- (Meta): type expression are now parsed and hence allowed inside arbitrary Haskell expression for padding width and precision. For example, `[fmt|Hello {pi:.{3 :: Int}}|]`.++## 0.10.0.1 -- 2021-10-30+ - Due to the dependencies refactor, `PyF` no have no dependencies other than the one packaged with GHC. The direct result is that `PyF` build time is reduced to 6s versus 4 minutes and 20s before. - Remove the dependency to `megaparsec` and replaces it by `parsec`. This should have minor impact on the error messages. - *Huge Change*. The parsing of embeded expression does not depend anymore on `haskell-src-ext` and `haskell-src-meta` and instead depends on the built-in `ghc` lib.
PyF.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name: PyF-version: 0.10.0.1+version: 0.10.1.0 synopsis: Quasiquotations for a python like interpolated string formatter description: Quasiquotations for a python like interpolated string formatter. license: BSD-3-Clause
Readme.md view
@@ -145,15 +145,20 @@ Will returns `-a\n-b`. Note how the first and last line breaks are ignored. -## Arbitrary value for precision+## Arbitrary value for precision and padding -The precision field can be any haskell expression instead of a fixed number:+The precision and padding width fields can be any Haskell expression (including variables) instead of a fixed number: ```haskell >>> [fmt|{pi:.{1+2}}|] 3.142 ``` +```haskell+>>> [fmt|{1986:^{2 * 10}d}|]+" 1986 "+```+ # Output type *PyF* aims at extending the string literal syntax. As such, it default to `String` type. However, if the `OverloadedString` is enabled, PyF will happilly generate `IsString t => t` instead. This means that you can use PyF to generate `String`, but also `Text` and why not `ByteString`, with all the caveats known to this extension.@@ -337,29 +342,25 @@ # Hacking -Everything works with nix. But you can also try with manual cabal / stack if you wish.+Everything works with nix and flakes. But you can also try with manual cabal / stack if you wish. -- `nix-shell` will open a shell with everything you need to work on PyF, including haskell-language-server. It may be a bit too much, so you can instead:-- `nix-shell ./ -A pyf_current.shell` which opens a shell without the haskell-language-server.-- `nix-shell ./ -A pyf_current.shell_hls` which opens a shell with the haskell-language-server, same as the default.-- `nix-shell ./ -A pyf_xx.shell[_hls]` opens a shell (with or without language server) for a difference GHC version. Uses `pyf_86`, `pyf_88`, `pyf_810`, `pyf_90` and `pyf_92`. Note that the language server may not be available for these version and it make take a bit to compile everything.+- `nix develop` will open a shell with everything you need to work on PyF, including haskell-language-server. It may be a bit too much, so you can instead:+- `nix develop .#pyf_XY` opens a shell with a specific GHC version and without haskell-language-server. That's mostly to test compatibility with different GHC version or open a shell without HLS if you are in a hurry. Replace `pyf_XY` by `pyf_86`, `pyf_88`, `pyf_810`, `pyf_90` or `pyf_92`. Once in the shell, use `cabal build`, `cabal test`, `cabal repl`. -There is a cachix available, used by CI:--- `cachix use guibou`+There is a cachix available, used by CI, and already configured in flakes. You can manually run `cachix use guibou` if you want. You can locally build and test everything using: -- `nix-build -A pyf_all`.+- `nix build .#pyf_all`. Don't hesitate to submit a PR not tested on all GHC versions. ## Formatting -The codebase is formatted with `ormolu` and this is checked in the CI. Please run:+The codebase is formatted with `ormolu`. Please run: -- `nix-shell ./ -A ormolu-fix`+- `nix run .\#run-ormolu` Before submitting.
src/PyF/Class.hs view
@@ -150,15 +150,16 @@ -- 'RealFrac' constraint. class PyfFormatFractional a where pyfFormatFractional ::+ (Integral paddingWidth, Integral precision) => Format t t' 'Fractional -> -- | Sign formatting SignMode -> -- | Padding- Maybe (Int, AlignMode k, Char) ->+ Maybe (paddingWidth, AlignMode k, Char) -> -- | Grouping Maybe (Int, Char) -> -- | Precision- Maybe Int ->+ Maybe precision -> a -> String @@ -183,11 +184,12 @@ -- 'Integral' constraint. class PyfFormatIntegral i where pyfFormatIntegral ::+ Integral paddingWidth => Format t t' 'Integral -> -- | Sign formatting SignMode -> -- | Padding- Maybe (Int, AlignMode k, Char) ->+ Maybe (paddingWidth, AlignMode k, Char) -> -- | Grouping Maybe (Int, Char) -> i ->
src/PyF/Formatters.hs view
@@ -1,10 +1,12 @@ {-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveLift #-} {-# LANGUAGE GADTs #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE KindSignatures #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE ViewPatterns #-} -- | --@@ -26,7 +28,6 @@ -- For integrals: -- -- * Binary / Hexa / Octal / Character representation-{-# LANGUAGE GeneralizedNewtypeDeriving #-} module PyF.Formatters ( -- * Generic formatting function formatString,@@ -126,7 +127,6 @@ -- Upper should come AFTER Alt, so this disallow any future alt Upper :: Format alt 'CanUpper f -> Format 'NoAlt 'NoUpper f - newtype ShowIntegral i = ShowIntegral i deriving (Real, Enum, Ord, Eq, Num, Integral) @@ -222,7 +222,7 @@ group (FractionalRepr s a b d) (Just (size, c)) = FractionalRepr s (groupIntercalate c size a) b d group i _ = i -padAndSign :: Format t t' t'' -> String -> SignMode -> Maybe (Int, AlignMode k, Char) -> Repr -> String+padAndSign :: Integral paddingWidth => Format t t' t'' -> String -> SignMode -> Maybe (paddingWidth, AlignMode k, Char) -> Repr -> String padAndSign format prefix sign padding repr = leftAlignMode <> prefixStr <> middleAlignMode <> content <> rightAlignMode where (signStr, content) = case repr of@@ -234,7 +234,7 @@ len = length prefixStr + length content (leftAlignMode, rightAlignMode, middleAlignMode) = case padding of Nothing -> ("", "", "")- Just (pad, padMode, padC) ->+ Just (fromIntegral -> pad, padMode, padC) -> let padNeeded = max 0 (pad - len) in case padMode of AlignLeft -> ("", replicate padNeeded padC, "")@@ -275,11 +275,12 @@ -- | Format an integral number formatIntegral ::+ Integral paddingWidth => Integral i => Format t t' 'Integral -> SignMode -> -- | Padding- Maybe (Int, AlignMode k, Char) ->+ Maybe (paddingWidth, AlignMode k, Char) -> -- | Grouping Maybe (Int, Char) -> i ->@@ -288,18 +289,18 @@ -- | Format a fractional number formatFractional ::- (RealFloat f) =>+ (RealFloat f, Integral paddingWidth, Integral precision) => Format t t' 'Fractional -> SignMode -> -- | Padding- Maybe (Int, AlignMode k, Char) ->+ Maybe (paddingWidth, AlignMode k, Char) -> -- | Grouping Maybe (Int, Char) -> -- | Precision- Maybe Int ->+ Maybe precision -> f -> String-formatFractional f sign padding grouping precision i = padAndSign f "" sign padding (group (reprFractional f precision i) grouping)+formatFractional f sign padding grouping precision i = padAndSign f "" sign padding (group (reprFractional f (fmap fromIntegral precision) i) grouping) -- | Format a string formatString ::
src/PyF/Internal/Meta.hs view
@@ -6,12 +6,14 @@ module PyF.Internal.Meta (toExp, baseDynFlags, translateTHtoGHCExt) where -#if MIN_VERSION_ghc(9,0,0)-import GHC.Hs.Type (HsWildCardBndrs (..), HsType (..))+#if MIN_VERSION_ghc(9,2,0)+import GHC.Hs.Type (HsWildCardBndrs (..), HsType (..), HsSigType(HsSig))+#elif MIN_VERSION_ghc(9,0,0)+import GHC.Hs.Type (HsWildCardBndrs (..), HsType (..), HsImplicitBndrs(HsIB)) #elif MIN_VERSION_ghc(8,10,0)-import GHC.Hs.Types (HsWildCardBndrs (..), HsType (..))+import GHC.Hs.Types (HsWildCardBndrs (..), HsType (..), HsImplicitBndrs (HsIB)) #else-import HsTypes (HsWildCardBndrs (..), HsType (..))+import HsTypes (HsWildCardBndrs (..), HsType (..), HsImplicitBndrs (HsIB)) #endif #if MIN_VERSION_ghc(8,10,0)@@ -58,6 +60,7 @@ import qualified Module #endif +import GHC.Stack #if MIN_VERSION_ghc(9,2,0) -- TODO: why this disapears in GHC >= 9.2?@@ -185,12 +188,17 @@ (FromThen a b) -> TH.FromThenR (toExp d $ unLoc a) (toExp d $ unLoc b) (FromTo a b) -> TH.FromToR (toExp d $ unLoc a) (toExp d $ unLoc b) (FromThenTo a b c) -> TH.FromThenToR (toExp d $ unLoc a) (toExp d $ unLoc b) (toExp d $ unLoc c)+#if MIN_VERSION_ghc(9, 2, 0)+toExp d (Expr.ExprWithTySig _ e (HsWC _ (unLoc -> HsSig _ _ (unLoc -> t)))) = TH.SigE (toExp d (unLoc e)) (toType t)+#elif MIN_VERSION_ghc(9, 0, 0)+toExp d (Expr.ExprWithTySig _ e (HsWC _ (HsIB _ (unLoc -> t)))) = TH.SigE (toExp d (unLoc e)) (toType t)+#endif toExp dynFlags e = todo "toExp" (showSDocDebug dynFlags . ppr $ e) -todo :: (Show e) => String -> e -> a+todo :: (HasCallStack, Show e) => String -> e -> a todo fun thing = error . concat $ [moduleName, ".", fun, ": not implemented: ", show thing] -noTH :: (Show e) => String -> e -> a+noTH :: (HasCallStack, Show e) => String -> e -> a noTH fun thing = error . concat $ [moduleName, ".", fun, ": no TemplateHaskell for: ", show thing] moduleName :: String
src/PyF/Internal/Parser.hs view
@@ -47,6 +47,7 @@ in Right expr +{- ORMOLU_DISABLE #-} #if MIN_VERSION_ghc(9,2,0) -- TODO messages? PFailed PState{loc=SrcLoc.psRealLoc -> srcLoc, errors=errorMessages} ->
src/PyF/Internal/ParserEx.hs view
@@ -1,10 +1,13 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE ViewPatterns #-} {-# LANGUAGE TupleSections #-}+{-# LANGUAGE ViewPatterns #-} {-# OPTIONS_GHC -Wno-missing-fields -Wno-name-shadowing -Wno-unused-imports #-}-{-# LANGUAGE CPP #-}-module PyF.Internal.ParserEx (fakeSettings, fakeLlvmConfig, parseExpression)-where++module PyF.Internal.ParserEx (fakeSettings, fakeLlvmConfig, parseExpression) where++{- ORMOLU_DISABLE -}+ #if MIN_VERSION_ghc(9,0,0) import GHC.Settings.Config import GHC.Driver.Session@@ -182,7 +185,6 @@ #else mkPState flags buffer location #endif- #if MIN_VERSION_ghc(9, 2, 0) parseExpression :: String -> DynFlags -> ParseResult (LocatedA (HsExpr GhcPs))
src/PyF/Internal/PythonSyntax.hs view
@@ -93,8 +93,8 @@ rawString :: Maybe (Char, Char) -> Parser Item rawString delimsM = do let delims = case delimsM of- Nothing -> []- Just (openingChar, closingChar) -> [openingChar, closingChar]+ Nothing -> []+ Just (openingChar, closingChar) -> [openingChar, closingChar] -- lookahead let p = some (noneOf delims)@@ -155,7 +155,7 @@ -- | Padding, containing the padding width, the padding char and the alignement mode data Padding = PaddingDefault- | Padding Integer (Maybe (Maybe Char, AnyAlign))+ | Padding (ExprOrValue Int) (Maybe (Maybe Char, AnyAlign)) deriving (Show) -- | Represents a value of type @t@ or an Haskell expression supposed to represents that value@@ -167,7 +167,7 @@ -- | Floating point precision data Precision = PrecisionDefault- | Precision (ExprOrValue Integer)+ | Precision (ExprOrValue Int) deriving (Show) {-@@ -256,7 +256,7 @@ alternateForm <- option NormalForm (AlternateForm <$ char '#') hasZero <- option False (True <$ char '0') let al = overrideAlignmentIfZero hasZero al'- w <- optionMaybe width+ w <- optionMaybe parseWidth grouping <- optionMaybe groupingOption prec <- option PrecisionDefault parsePrecision @@ -274,6 +274,15 @@ Left typeError -> fail typeError +parseWidth :: Parser (ExprOrValue Int)+parseWidth = do+ exts <- asks enabledExtensions+ Just (charOpening, charClosing) <- asks delimiters+ choice+ [ Value <$> width+ , char charOpening *> (HaskellExpr <$> evalExpr exts (someTill (satisfy (/= charClosing)) (char charClosing) <?> "an haskell expression"))+ ]+ parsePrecision :: Parser Precision parsePrecision = do exts <- asks enabledExtensions@@ -374,16 +383,16 @@ Space <$ char ' ' ] -width :: Parser Integer+width :: Parser Int width = integer -integer :: Parser Integer+integer :: Parser Int integer = read <$> some (oneOf ['0' .. '9']) -- incomplete: see: https://docs.python.org/3/reference/lexical_analysis.html#grammar-token-integer groupingOption :: Parser Char groupingOption = oneOf ("_," :: String) -precision :: Parser Integer+precision :: Parser Int precision = integer type_ :: Parser TypeFlag
src/PyF/Internal/QQ.hs view
@@ -180,9 +180,7 @@ -- | Precision to maybe splicePrecision :: Maybe Int -> Precision -> Q Exp splicePrecision def PrecisionDefault = [|def|]-splicePrecision _ (Precision p) = case p of- Value n -> [|Just n|]- HaskellExpr e -> [|Just $(pure e)|]+splicePrecision _ (Precision p) = [|Just $(exprToInt p)|] toGrp :: Maybe Char -> Int -> Q Exp toGrp mb a = [|grp|]@@ -215,41 +213,43 @@ StringF prec -> [|Formatters.formatString (newPaddingKForString $(paddingToPaddingK padding)) $(splicePrecision Nothing prec) . pyfToString|] newPaddingQ :: Padding -> Q Exp-newPaddingQ pad = [|pad'|]- where- pad' = newPaddingUnQ pad--newPaddingUnQ :: Padding -> Maybe (Integer, AnyAlign, Char)-newPaddingUnQ padding = case padding of- PaddingDefault -> Nothing+newPaddingQ padding = case padding of+ PaddingDefault -> [|Nothing|] (Padding i al) -> case al of- Nothing -> Just (i, AnyAlign Formatters.AlignRight, ' ') -- Right align and space is default for any object, except string- Just (Nothing, a) -> Just (i, a, ' ')- Just (Just c, a) -> Just (i, a, c)+ Nothing -> [|Just ($(exprToInt i), AnyAlign Formatters.AlignRight, ' ')|] -- Right align and space is default for any object, except string+ Just (Nothing, a) -> [|Just ($(exprToInt i), a, ' ')|]+ Just (Just c, a) -> [|Just ($(exprToInt i), a, c)|] +exprToInt :: ExprOrValue Int -> Q Exp+-- Note: this is a literal provided integral. We use explicit case to ::Int so it won't warn about defaulting+exprToInt (Value i) = [|$(pure $ LitE (IntegerL (fromIntegral i))) :: Int|]+exprToInt (HaskellExpr e) = [|$(pure e)|]+ data PaddingK k where PaddingDefaultK :: PaddingK 'Formatters.AlignAll- PaddingK :: Integer -> Maybe (Maybe Char, Formatters.AlignMode k) -> PaddingK k+ PaddingK :: Int -> Maybe (Maybe Char, Formatters.AlignMode k) -> PaddingK k paddingToPaddingK :: Padding -> Q Exp paddingToPaddingK p = case p of PaddingDefault -> [|PaddingDefaultK|]- Padding i Nothing -> [|PaddingK i Nothing :: PaddingK 'Formatters.AlignAll|]- Padding i (Just (c, AnyAlign a)) -> [|PaddingK i (Just (c, a))|]+ Padding i Nothing -> [|PaddingK (fromIntegral $(exprToInt i)) Nothing :: PaddingK 'Formatters.AlignAll|]+ Padding i (Just (c, AnyAlign a)) -> [|PaddingK (fromIntegral $(exprToInt i)) (Just (c, a))|] -paddingKToPadding :: PaddingK k -> Padding+paddingKToPadding :: PaddingK k -> Maybe (Int, AnyAlign, Char) paddingKToPadding p = case p of- PaddingDefaultK -> PaddingDefault- PaddingK i Nothing -> Padding i Nothing- PaddingK i (Just (c, a)) -> Padding i (Just (c, AnyAlign a))+ PaddingDefaultK -> Nothing+ (PaddingK i al) -> case al of+ Nothing -> Just (i, AnyAlign Formatters.AlignRight, ' ') -- Right align and space is default for any object, except string+ Just (Nothing, a) -> Just (i, AnyAlign a, ' ')+ Just (Just c, a) -> Just (i, AnyAlign a, c) -formatAnyIntegral :: PyfFormatIntegral i => Formatters.Format t t' 'Formatters.Integral -> Formatters.SignMode -> Maybe (Integer, AnyAlign, Char) -> Maybe (Int, Char) -> i -> String-formatAnyIntegral f s Nothing grouping i = pyfFormatIntegral f s Nothing grouping i-formatAnyIntegral f s (Just (padSize, AnyAlign alignMode, c)) grouping i = pyfFormatIntegral f s (Just (fromIntegral padSize, alignMode, c)) grouping i+formatAnyIntegral :: forall i a t t'. Integral a => PyfFormatIntegral i => Formatters.Format t t' 'Formatters.Integral -> Formatters.SignMode -> Maybe (a, AnyAlign, Char) -> Maybe (Int, Char) -> i -> String+formatAnyIntegral f s Nothing grouping i = pyfFormatIntegral @i @a f s Nothing grouping i+formatAnyIntegral f s (Just (padSize, AnyAlign alignMode, c)) grouping i = pyfFormatIntegral f s (Just (padSize, alignMode, c)) grouping i -formatAnyFractional :: (PyfFormatFractional i) => Formatters.Format t t' 'Formatters.Fractional -> Formatters.SignMode -> Maybe (Integer, AnyAlign, Char) -> Maybe (Int, Char) -> Maybe Int -> i -> String-formatAnyFractional f s Nothing grouping p i = pyfFormatFractional f s Nothing grouping p i-formatAnyFractional f s (Just (padSize, AnyAlign alignMode, c)) grouping p i = pyfFormatFractional f s (Just (fromIntegral padSize, alignMode, c)) grouping p i+formatAnyFractional :: forall a b i t t'. (Integral a, Integral b, PyfFormatFractional i) => Formatters.Format t t' 'Formatters.Fractional -> Formatters.SignMode -> Maybe (a, AnyAlign, Char) -> Maybe (Int, Char) -> Maybe b -> i -> String+formatAnyFractional f s Nothing grouping p i = pyfFormatFractional @i @a @b f s Nothing grouping p i+formatAnyFractional f s (Just (padSize, AnyAlign alignMode, c)) grouping p i = pyfFormatFractional f s (Just (padSize, alignMode, c)) grouping p i class FormatAny i k where formatAny :: Formatters.SignMode -> PaddingK k -> Maybe (Int, Char) -> Maybe Int -> i -> String@@ -261,10 +261,10 @@ formatAny2 :: Proxy c -> Formatters.SignMode -> PaddingK k -> Maybe (Int, Char) -> Maybe Int -> i -> String instance (Show t, Integral t) => FormatAny2 'PyFIntegral t k where- formatAny2 _ s a p _precision = formatAnyIntegral Formatters.Decimal s (newPaddingUnQ (paddingKToPadding a)) p+ formatAny2 _ s a p _precision = formatAnyIntegral Formatters.Decimal s (paddingKToPadding a) p instance (PyfFormatFractional t) => FormatAny2 'PyFFractional t k where- formatAny2 _ s a = formatAnyFractional Formatters.Generic s (newPaddingUnQ (paddingKToPadding a))+ formatAny2 _ s a = formatAnyFractional Formatters.Generic s (paddingKToPadding a) newPaddingKForString :: PaddingK 'Formatters.AlignAll -> Maybe (Int, Formatters.AlignMode 'Formatters.AlignAll, Char) newPaddingKForString padding = case padding of
test/Spec.hs view
@@ -243,6 +243,11 @@ do let n = 3 :: Int [fmt|{pi:.{n}}|] `shouldBe` "3.142"+ describe "variable padding" $ + it "works" $ + do+ let n = 5 :: Integer+ [fmt|Bonjour {'a':>{n}}|] `shouldBe` "Bonjour a" it "escape chars" $ [fmt|}}{{}}{{|] `shouldBe` "}{}{" describe "custom delimiters" $ do@@ -387,9 +392,9 @@ it "tuples" $ do [fmt|{fst (1, 2)}|] `shouldBe` "1" --- Disabled because it does not build with GHC < 8.10--- xit "tuples section" $ do--- [fmt|{fst ((,2) 1)}|] `shouldBe` "1"+ -- Disabled because it does not build with GHC < 8.10+ -- xit "tuples section" $ do+ -- [fmt|{fst ((,2) 1)}|] `shouldBe` "1" describe "multiline trimming" $ do it "works with overloading" $ do@@ -402,26 +407,30 @@ [fmtTrim| hello\ - |] `shouldBe` "hello\n"+ |]+ `shouldBe` "hello\n" it "do not take too much indent in account" $ do [fmtTrim| hello - a - b - c- |] `shouldBe` "hello\n- a\n - b\n- c\n"+ |]+ `shouldBe` "hello\n- a\n - b\n- c\n" it "works with empty lines" $ do [fmtTrim| hello - |] `shouldBe` "hello\n\n\n"+ |]+ `shouldBe` "hello\n\n\n" it "works with empty last lines" $ do [fmtTrim| hello -|] `shouldBe` "hello\n\n\n"+|]+ `shouldBe` "hello\n\n\n" it "works" $ do [fmtTrim| hello@@ -461,17 +470,23 @@ it "Do not touch single lines" $ do [fmtTrim| hello|] `shouldBe` " hello" describe "raw" $ do- it "does not escape anything" $ [raw|hello+ it "does not escape anything" $+ [raw|hello - a \n {\ - b }- |] `shouldBe` "hello\n - a \\n {\\\n - b }\n "+ |]+ `shouldBe` "hello\n - a \\n {\\\n - b }\n " describe "str" $ do- it "basic escaping but no indentation neither formatting" $ [str|hello+ it "basic escaping but no indentation neither formatting" $+ [str|hello - a \n {\ - b {pi}- |] `shouldBe` "hello\n - a \n { - b {pi}\n "+ |]+ `shouldBe` "hello\n - a \n { - b {pi}\n " describe "strTrim" $ do- it "basic escaping neither formatting" $ [strTrim|+ it "basic escaping neither formatting" $+ [strTrim| - a \b { - b {pi}- |] `shouldBe` "- a \b {\n- b {pi}\n"+ |]+ `shouldBe` "- a \b {\n- b {pi}\n"
test/SpecUtils.hs view
@@ -8,14 +8,15 @@ where import Language.Haskell.TH-import PyF.Internal.QQ #ifdef PYTHON_TEST import Language.Haskell.TH.Syntax import System.Exit import System.Process #endif-import Test.Hspec+ import PyF (fmtConfig)+import PyF.Internal.QQ+import Test.Hspec -- * Utils
test/golden/{helloCOLON=100}.golden view
@@ -1,9 +1,9 @@ INITIALPATH:7:22: error: • String type is incompatible with inside padding (=).- • In the first argument of ‘putStrLn’, namely ‘(((((PyF.Internal.QQ.formatAny PyF.Formatters.Minus) ((PyF.Internal.QQ.PaddingK 100) (Just (Nothing, PyF.Formatters.AlignInside)))) Nothing) Nothing) hello)’- In the expression: putStrLn (((((PyF.Internal.QQ.formatAny PyF.Formatters.Minus) ((PyF.Internal.QQ.PaddingK 100) (Just (Nothing, PyF.Formatters.AlignInside)))) Nothing) Nothing) hello)- In an equation for ‘main’: main = putStrLn (((((PyF.Internal.QQ.formatAny PyF.Formatters.Minus) ((PyF.Internal.QQ.PaddingK 100) (Just (Nothing, PyF.Formatters.AlignInside)))) Nothing) Nothing) hello)+ • In the first argument of ‘putStrLn’, namely ‘(((((PyF.Internal.QQ.formatAny PyF.Formatters.Minus) ((PyF.Internal.QQ.PaddingK (fromIntegral (100 :: Int))) (Just (Nothing, PyF.Formatters.AlignInside)))) Nothing) Nothing) hello)’+ In the expression: putStrLn (((((PyF.Internal.QQ.formatAny PyF.Formatters.Minus) ((PyF.Internal.QQ.PaddingK (fromIntegral (100 :: Int))) (Just (Nothing, PyF.Formatters.AlignInside)))) Nothing) Nothing) hello)+ In an equation for ‘main’: main = putStrLn (((((PyF.Internal.QQ.formatAny PyF.Formatters.Minus) ((PyF.Internal.QQ.PaddingK (fromIntegral (100 :: Int))) (Just (Nothing, PyF.Formatters.AlignInside)))) Nothing) Nothing) hello) | 7 | main = putStrLn [fmt|{hello:=100}|] | ^^^^^^^^^^^^^^