fmt 0.4.0.0 → 0.5.0.0
raw patch · 5 files changed
+123/−89 lines, 5 filesdep ~hspecPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: hspec
API changes (from Hackage documentation)
- Fmt: indent :: Int -> Builder -> Builder
- Fmt: indent' :: Int -> Text -> Builder -> Builder
- Fmt.Internal: indent' :: Int -> Text -> Builder -> Builder
+ Fmt: indentF :: Int -> Builder -> Builder
+ Fmt: indentF' :: Int -> Text -> Builder -> Builder
+ Fmt: unlinesF :: (Foldable f, Buildable a) => f a -> Builder
+ Fmt: unwordsF :: (Foldable f, Buildable a) => f a -> Builder
+ Fmt.Internal: indentF' :: Int -> Text -> Builder -> Builder
- Fmt: blockListF' :: forall f a. (Foldable f) => (a -> Builder) -> f a -> Builder
+ Fmt: blockListF' :: forall f a. Foldable f => Text -> (a -> Builder) -> f a -> Builder
Files
- CHANGELOG.md +28/−8
- fmt.cabal +1/−1
- lib/Fmt.hs +80/−60
- lib/Fmt/Internal.hs +5/−5
- tests/Main.hs +9/−15
CHANGELOG.md view
@@ -1,6 +1,19 @@+# 0.5.0.0++* From this version on, `blockListF` never puts blank lines between items.+ If you want blank lines between items, I'm afraid that you'll have to add+ them manually (by e.g. adding a blank line to each item).++* Now `blockListF'` can be used to create lists with custom bullets.++* Added `unwordsF` and `unlinesF`.++* Added the `F` suffix to `indent` and `indent'`.+ # 0.4.0.0 -* Renamed `#|` and `|#` to `+|` and `|+` because HLint can't handle `#|` and everyone uses HLint apparently.+* Renamed `#|` and `|#` to `+|` and `|+` because HLint can't handle `#|` and+ everyone uses HLint apparently. # 0.3.0.0 @@ -14,7 +27,8 @@ * Added `genericF` for formatting arbitrary data. -* Changed `%<` and `>%` to `#|` and `|#` because they turn out to be easier to type.+* Changed `%<` and `>%` to `#|` and `|#` because they turn out to be easier+ to type. * Added a migration guide from `formatting`. @@ -24,7 +38,8 @@ # 0.0.0.4 -* Added `format` from `text-format`, because in some cases it's nicer than brackets.+* Added `format` from `text-format`, because in some cases it's nicer than+ brackets. * Renamed `padCenterF` to `padBothF`. @@ -51,23 +66,28 @@ * Added `fmt` and `fmtLn`. -* Made all operators associate to the right (`Builder` documentation says it's faster than the opposite).+* Made all operators associate to the right (`Builder` documentation says+ it's faster than the opposite). * Reexported `Buildable` and `Builder`. # 0.0.0.2 -* Added `>%%<` so that it'd be possible to write `%<a>%%<b>%` instead of weird `%<a%<b>%`.+* Added `>%%<` so that it'd be possible to write `%<a>%%<b>%` instead of+ weird `%<a%<b>%`. -* Added `%<< ... >>%`, which work work `Show` instead of `Buildable`. If you don't care about speed and just want to output something, use them.+* Added `%<< ... >>%`, which work work `Show` instead of `Buildable`. If you+ don't care about speed and just want to output something, use them. -* Added an `IO ()` instance in `Fmt.IO`. If you import that module, raw formatted strings would print themselves.+* Added an `IO ()` instance in `Fmt.IO`. If you import that module, raw+ formatted strings would print themselves. * Added tests. * Changed fixities of operators so that `%<n+1>%` would work. -* Changed license to BSD3 since all our dependencies are BSD3 and we can't use MIT.+* Changed license to BSD3 since all our dependencies are BSD3 and we can't+ use MIT. # 0.0.0.1
fmt.cabal view
@@ -1,5 +1,5 @@ name: fmt-version: 0.4.0.0+version: 0.5.0.0 synopsis: A new formatting library description: A new formatting library that tries to be simple to understand while still
lib/Fmt.hs view
@@ -82,12 +82,16 @@ Buildable(..), -- * Formatters- indent, indent',- nameF, -- ** Time module Fmt.Time, + -- ** Text+ indentF, indentF',+ nameF,+ unwordsF,+ unlinesF,+ -- ** Lists listF, listF', blockListF, blockListF',@@ -157,6 +161,7 @@ import qualified Data.IntSet as IntSet import Data.Sequence (Seq) -- Text+import qualified Data.Text as T import qualified Data.Text.Lazy as TL -- 'Buildable' and text-format import Data.Text.Buildable@@ -186,7 +191,8 @@ {- $overloadedstrings -You need @OverloadedStrings@ enabled to use this library. There are three ways to do it:+You need @OverloadedStrings@ enabled to use this library. There are three+ways to do it: * __In GHCi:__ do @:set -XOverloadedStrings@. @@ -248,8 +254,8 @@ The resulting formatted string is polymorphic and can be used as 'String', 'Text', 'Builder' or even 'IO' (i.e. the string will be printed to the-screen). However, when printing it is recommended to use 'fmt' or 'fmtLn' for-clarity.+screen). However, when printing it is recommended to use 'fmt' or 'fmtLn'+for clarity. @fmt@ provides lots of formatters (which are simply functions that produce 'Builder'):@@ -291,7 +297,6 @@ * @plural@ and @asInt@ (but instead of @asInt@ you can use 'fromEnum') * @prefixBin@, @prefixOrd@, @prefixHex@, and @bytes@ * formatters that use @Scientific@ (@sci@ and @scifmt@)-* formatters that deal with time (anything from @Formatting.Time@) They will be added later. (On the other hand, @fmt@ provides some useful formatters not available in @formatting@, such as 'listF', 'mapF', 'tupleF'@@ -323,8 +328,8 @@ Meet Alice! Otherwise the type of the formatted string would be resolved to @IO ()@ and-printed without a newline, which is not very convenient when you're in-GHCi. On the other hand, it's useful for quick-and-dirty scripts:+printed without a newline, which is not very convenient when you're in GHCi.+On the other hand, it's useful for quick-and-dirty scripts: @ main = do@@ -499,9 +504,27 @@ {-# INLINE fmtLn #-} ------------------------------------------------------------------------------- Formatters+-- Text formatters ---------------------------------------------------------------------------- +{- |+Indent a block of text.++>>> fmt $ "This is a list:\n" <> indentF 4 (blockListF [1,2,3])+This is a list:+ - 1+ - 2+ - 3++The output will always end with a newline, even when the input doesn't.+-}+indentF :: Int -> Builder -> Builder+indentF n a = case TL.lines (toLazyText a) of+ [] -> fromLazyText (spaces <> "\n")+ xs -> fromLazyText $ TL.unlines (map (spaces <>) xs)+ where+ spaces = TL.replicate (fromIntegral n) (TL.singleton ' ')+ {- | Attach a name to anything: >>> fmt $ nameF "clients" $ blockListF ["Alice", "Bob", "Zalgo"]@@ -517,6 +540,35 @@ ls -> k <> ":\n" <> mconcat [" " <> fromLazyText s <> "\n" | s <- ls] +{- | Put words between elements.++>>> fmt $ unwordsF ["hello", "world"]+hello world++Of course, it works on anything 'Buildable':++>>> fmt $ unwordsF [1, 2]+1 2+-}+unwordsF :: (Foldable f, Buildable a) => f a -> Builder+unwordsF = mconcat . intersperse " " . map build . toList++{-# SPECIALIZE unwordsF :: Buildable a => [a] -> Builder #-}++{- | Arrange elements on separate lines.++>>> fmt $ unlines ["hello", "world"]+hello+world+-}+unlinesF :: (Foldable f, Buildable a) => f a -> Builder+unlinesF = mconcat . map (nl . build) . toList+ where+ nl x | "\n" `TL.isSuffixOf` toLazyText x = x+ | otherwise = x <> "\n"++{-# SPECIALIZE unlinesF :: Buildable a => [a] -> Builder #-}+ ---------------------------------------------------------------------------- -- List formatters ----------------------------------------------------------------------------@@ -554,8 +606,8 @@ The documentation for 'Builder' says that it's preferrable to associate 'Builder' appends to the right (i.e. @a <> (b <> c)@). The maximum possible-association-to-the-right is achieved when we avoid appending builders-until the last second (i.e. in the latter scenario):+association-to-the-right is achieved when we avoid appending builders until+the last second (i.e. in the latter scenario): -- (a1 <> x) <> (a2 <> x) <> ... mconcat [a <> x | a <- as]@@ -573,41 +625,41 @@ - 2 - 3 -It automatically handles multiline list elements:+Multi-line elements are indented correctly: @ >>> __fmt $ blockListF ["hello\\nworld", "foo\\nbar\\nquix"]__ - hello world- - foo bar quix @ -} blockListF :: forall f a. (Foldable f, Buildable a) => f a -> Builder-blockListF = blockListF' build+blockListF = blockListF' "-" build {-# INLINE blockListF #-} {- | A version of 'blockListF' that lets you supply your own building function-for list elements.+for list elements (instead of 'build') and choose the bullet character+(instead of @"-"@). -}-blockListF' :: forall f a. (Foldable f) => (a -> Builder) -> f a -> Builder-blockListF' fbuild xs- | null items = "[]\n"- | True `elem` mls = mconcat (intersperse "\n" items)- | otherwise = mconcat items+blockListF'+ :: forall f a. Foldable f+ => T.Text -- ^ Bullet+ -> (a -> Builder) -- ^ Builder for elements+ -> f a -- ^ Structure with elements+ -> Builder+blockListF' bullet fbuild xs = if null items then "[]\n" else mconcat items where- (mls, items) = unzip $ map buildItem (toList xs)- -- Returns 'True' if the item is multiline- buildItem :: a -> (Bool, Builder)+ items = map buildItem (toList xs)+ spaces = mconcat $ replicate (T.length bullet + 1) (singleton ' ') buildItem x = case TL.lines (toLazyText (fbuild x)) of- [] -> (False, "-\n")- (l:ls) -> (not (null ls),- "- " <> fromLazyText l <> "\n" <>- mconcat [" " <> fromLazyText s <> "\n" | s <- ls])+ [] -> bullet |+ "\n"+ (l:ls) -> bullet |+ " " +| l |+ "\n" <>+ mconcat [spaces <> fromLazyText s <> "\n" | s <- ls] -{-# SPECIALIZE blockListF' :: (a -> Builder) -> [a] -> Builder #-}+{-# SPECIALIZE blockListF' :: T.Text -> (a -> Builder) -> [a] -> Builder #-} {- | A JSON-style formatter for lists. @@ -628,8 +680,6 @@ bar quix ]--(Note that, unlike 'blockListF', it doesn't add blank lines in such cases.) -} jsonListF :: forall f a. (Foldable f, Buildable a) => f a -> Builder jsonListF = jsonListF' build@@ -1085,28 +1135,6 @@ {-# INLINE unlessF #-} ------------------------------------------------------------------------------- Utilities-------------------------------------------------------------------------------{- |-Indent already formatted text.-->>> fmt $ "This is a list:\n" <> indent 4 (blockListF [1,2,3])-This is a list:- - 1- - 2- - 3--The output will always end with a newline, even when the input doesn't.--}-indent :: Int -> Builder -> Builder-indent n a = case TL.lines (toLazyText a) of- [] -> fromLazyText (spaces <> "\n")- xs -> fromLazyText $ TL.unlines (map (spaces <>) xs)- where- spaces = TL.replicate (fromIntegral n) (TL.singleton ' ')------------------------------------------------------------------------------ -- Generic formatting ---------------------------------------------------------------------------- @@ -1294,14 +1322,6 @@ ---------------------------------------------------------------------------- -- TODOs ------------------------------------------------------------------------------{- list/map-~~~~~~~~~~~~~~~~~~~~-* maybe add something like blockMapF_ and blockListF_ that would add- a blank line automatically? or `---` and `:::` or something?-* should also add something to _not_ add a blank line between list- entries (e.g. when they are 'name'd and can be clearly differentiated)--} {- docs ~~~~~~~~~~~~~~~~~~~~
lib/Fmt/Internal.hs view
@@ -16,8 +16,8 @@ # define _OVERLAPS_ {-# OVERLAPS #-} #endif -{- | A module providing access to internals (in case you really need them). Can-change at any time, though probably won't.+{- | A module providing access to internals (in case you really need them).+Can change at any time, though probably won't. It also provides some functions that are used in 'Fmt.Time' (so that 'Fmt.Time' wouldn't need to import 'Fmt').@@ -43,7 +43,7 @@ atBase, showSigned', intToDigit',- indent',+ indentF', -- * Functions used in 'Fmt.Time' fixedF,@@ -257,8 +257,8 @@ The output will always end with a newline, even when the input doesn't. -}-indent' :: Int -> T.Text -> Builder -> Builder-indent' n pref a = case TL.lines (toLazyText a) of+indentF' :: Int -> T.Text -> Builder -> Builder+indentF' n pref a = case TL.lines (toLazyText a) of [] -> fromText pref <> "\n" (x:xs) -> fromLazyText $ TL.unlines $ (TL.fromStrict pref <> x) : map (spaces <>) xs
tests/Main.hs view
@@ -114,18 +114,18 @@ ---------------------------------------------------------------------------- test_indent :: Spec-test_indent = describe "'indent'" $ do+test_indent = describe "'indentF'" $ do it "simple examples" $ do- indent 0 "hi" ==#> "hi\n"- indent 0 "\nhi\n\n" ==#> "\nhi\n\n"- indent 2 "hi" ==#> " hi\n"- indent 2 "hi\n" ==#> " hi\n"- indent 2 "" ==#> " \n"- indent 2 "hi\nbye" ==#> " hi\n bye\n"- indent 2 "hi\nbye\n" ==#> " hi\n bye\n"+ indentF 0 "hi" ==#> "hi\n"+ indentF 0 "\nhi\n\n" ==#> "\nhi\n\n"+ indentF 2 "hi" ==#> " hi\n"+ indentF 2 "hi\n" ==#> " hi\n"+ indentF 2 "" ==#> " \n"+ indentF 2 "hi\nbye" ==#> " hi\n bye\n"+ indentF 2 "hi\nbye\n" ==#> " hi\n bye\n" it "formatting a block" $ do ("Some numbers:\n"<>- indent 2 (+ indentF 2 ( "odd: "+|n|+"\n"<> "even: "+|n+1|+"")) ==#> "Some numbers:\n odd: 25\n even: 26\n" @@ -308,11 +308,9 @@ blockListF (["a\n x"," b\nxx\ny y ","c\n\n"] :: [Text]) ==#> [text| - a x- - b xx y y_- - c __ |]@@ -321,22 +319,18 @@ blockListF (["a\nx","b"] :: [Text]) ==#> [text| - a x- - b |] blockListF (["a\nx","b\n"] :: [Text]) ==#> [text| - a x- - b |] blockListF (["a"," b\nxx\ny y ","c\n\n"] :: [Text]) ==#> [text| - a- - b xx y y_- - c __ |]