packages feed

logfmt (empty) → 0.0.1

raw patch · 11 files changed

+6963/−0 lines, 11 filesdep +ansi-terminaldep +basedep +bytestringsetup-changed

Dependencies added: ansi-terminal, base, bytestring, fast-logger, profunctors, time

Files

+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Revision history for logfmt++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,29 @@+BSD 3-Clause License++Copyright (c) 2021, Chris McKinlay+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++1. Redistributions of source code must retain the above copyright notice, this+   list of conditions and the following disclaimer.++2. Redistributions in binary form must reproduce the above copyright notice,+   this list of conditions and the following disclaimer in the documentation+   and/or other materials provided with the distribution.++3. Neither the name of the copyright holder nor the names of its+   contributors may be used to endorse or promote products derived from+   this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,1 @@+# logfmt
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ logfmt.cabal view
@@ -0,0 +1,45 @@+cabal-version:       >=1.10++name:           logfmt+version:        0.0.1+synopsis:       Formatting+description:    Please see the README on GitHub at https://github.com/cmk/logfmt#readme+category:       Text, System+homepage:       https://github.com/cmk/logfmt#readme+bug-reports:    https://github.com/cmk/logfmt/issues+author:         Chris McKinlay+maintainer:     chris.mckinlay@gmail.com+copyright:      2020-2021 Chris McKinlay+license:        BSD3+license-file:   LICENSE+build-type:     Simple+extra-source-files:+      README.md+      ChangeLog.md+tested-with:+      GHC == 8.10.1+source-repository head+  type: git+  location: https://github.com/cmk/logfmt++library+  exposed-modules:+      Data.Fmt+      Data.Fmt.Ansi+      Data.Fmt.Attr+      Data.Fmt.Code+      Data.Fmt.Html+      Data.Fmt.Time++  other-modules:+      Paths_logfmt+  hs-source-dirs:+      src+  build-depends:+      base >=4.14 && <5+    , bytestring+    , profunctors+    , fast-logger+    , ansi-terminal+    , time+  default-language: Haskell2010
+ src/Data/Fmt.hs view
@@ -0,0 +1,815 @@+{-# LANGUAGE DerivingVia #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeFamilies #-}++module Data.Fmt (+    Term,++    -- * Type+    LogFmt,+    Fmt (..),+    spr,+    printf,+    runFmt,+    runLogFmt,+    +    -- * Fmt+    fmt,+    logFmt,+    (%),+    apply,+    bind,+    cat,+    refmt,+    replace1,+    splitWith,++    -- * Fmt1+    Fmt1,+    Fmt2,+    fmt1,+    fmt2,+    fmt1_,+    fmt2_,+    (.%),+    cat1,+    cat1With,+    split1With,++    -- * Html+    Html,+    toHtml,+    comment,+    Attr (..),+    Element (..),+    (!?),++    -- * Formatting+    hsep,+    vsep,+    hang,+    indent,+    prefix,+    suffix,+    enclose,+    tuple,+    quotes,+    quotes',+    parens,+    braces,+    brackets,+    backticks,++    -- * Collections+    left1,+    right1,+    either1,+    maybe1,+    list1,+    jsonList,+    yamlList,+    jsonMap,+    yamlMap,++    -- * Re-exports+    LogStr,+    fromLogStr,+    ToLogStr (..),+    IsString (..),+) where++import Control.Applicative (Const (..), getConst)+import Control.Arrow+import Control.Category (Category (), (<<<), (>>>))+import Data.ByteString (ByteString)+import Data.ByteString.Builder (Builder)+import Data.Foldable (toList)+import Data.Profunctor+import Data.String+import GHC.Exts (IsList, Item)+import System.Log.FastLogger (LogStr, ToLogStr (..), fromLogStr)+import qualified Control.Category as C+import qualified Data.ByteString.Builder as BL+import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString.Lazy.Char8 as BL+import qualified GHC.Exts as IsList (toList)+import qualified Numeric as N++{- $setup+ >>> import Data.Printf+ >>> :load Data.Fmt+-}++type Term = IO ()++type LogFmt = Fmt LogStr++{- | A formatter, implemented as an indexed continuation++ When you construct formatters the first type+ parameter, @r@, will remain polymorphic.  The second type+ parameter, @a@, will change to reflect the types of the data that+ will be formatted.  For example, in++ @+ person :: Fmt2 ByteString Int+ person = \"Person's name is \" % t % \", age is \" % d+ @++ the first type parameter remains polymorphic, and the second type+ parameter is @ByteString -> Int -> r@, which indicates that it formats a+ 'ByteString' and an 'Int'.++ When you run the formatter, for example with 'format', you provide+ the arguments and they will be formatted into a string.++ >>> format ("This person's name is " % s % ", their age is " % d) "Anne" 22+ "This person's name is Anne, their age is 22"+-}+newtype Fmt m a b = Fmt {unFmt :: (m -> a) -> b}++deriving via (Costar ((->) m) a) instance Functor (Fmt m a)+deriving via (Costar ((->) m) a) instance Applicative (Fmt m a)+deriving via (Costar ((->) m) a) instance Monad (Fmt m a)+deriving via (Costar ((->) m)) instance Profunctor (Fmt m)+deriving via (Costar ((->) m)) instance Closed (Fmt m)+deriving via (Costar ((->) m)) instance Costrong (Fmt m)+deriving via (Costar ((->) m)) instance Cochoice (Fmt m)++instance (IsString s, Show a) => Show (Fmt LogStr s a) where+    show = show . runLogFmt++instance (IsString m, a ~ b) => IsString (Fmt m a b) where+    fromString = fmt . fromString++instance Semigroup m => Semigroup (Fmt1 m s a) where+    (<>) = (.%)++instance Monoid m => Monoid (Fmt1 m s a) where+    mempty = Fmt (\k _ -> k mempty)++instance Monoid m => Category (Fmt m) where+    id = fmt mempty+    (.) = (%)++instance Monoid m => Arrow (Fmt m) where+    arr f = Fmt $ \k -> f (k mempty)+    x *** y = dimap fst (,) x <*> lmap snd y++instance Monoid m => Strong (Fmt m) where+    first' x = x *** C.id+    second' x = C.id *** x++{- | Run a monadic formatting expression.++   Like the method of 'Text.Printf.PrintfType', 'spr' executes the formatting+   commands contained in the expression and returns the result as a monadic+   variable.++   For example, note that the 'Data.Fmt.Html.li' tag repeats, while the+   'Data.Fmt.Html.ul' tag does not: ++   >>> :{+    let contact = p "You can reach me at" % ul . spr . li $ do+          c1 <- a ! href @String "https://example.com" $ "Website"+          c2 <- a ! href @String "mailto:cmk@example.com" $ "Email"+          pure $ c1 <> c2+    in runLogStr contact+   :}+   "<p>You can reach me at</p><ul><li><a href=\"https://foo.com\">Web</a></li><li><a href=\"mailto:cmk@foo.com\">Email</a></li></ul>"+-}+spr :: IsString s => Fmt LogStr s m -> Fmt m a a+spr = fmt . runLogFmt++-- | Run a formatter and print out the text to stdout.+{-# INLINE printf #-}+printf :: Fmt LogStr Term a -> a+printf = flip unFmt (B.putStrLn . fromLogStr)++-- | Run a 'Fmt'.+{-# INLINE runFmt #-}+runFmt :: Fmt m m a -> a+runFmt = flip unFmt id++-- | Run a 'LogFmt'.+{-# INLINE runLogFmt #-}+runLogFmt :: IsString s => Fmt LogStr s a -> a+runLogFmt = flip unFmt (fromString . B.unpack . fromLogStr)+{-# SPECIALIZE runLogFmt :: Fmt LogStr BL.ByteString a -> a #-}+{-# SPECIALIZE runLogFmt :: Fmt LogStr ByteString a -> a #-}+{-# SPECIALIZE runLogFmt :: Fmt LogStr String a -> a #-}+{-# SPECIALIZE runLogFmt :: Fmt LogStr LogStr a -> a #-}+{-# SPECIALIZE runLogFmt :: Fmt LogStr Builder a -> a #-}++-- | Format a constant value of type @m@.+{-# INLINE fmt #-}+fmt :: m -> Fmt m a a+fmt m = Fmt ($ m)++-- | Format a constant value of type @m@.+{-# INLINE logFmt #-}+logFmt :: ToLogStr m => m -> Fmt LogStr a a+logFmt = fmt . toLogStr++-- | Concatenate two formatters.+infixr 0 %++{-# INLINE (%) #-}+(%) :: Semigroup m => Fmt m b c -> Fmt m a b -> Fmt m a c+f % g =+    f+        `bind` \a ->+            g+                `bind` \b -> fmt (a <> b)++-- | Apply a 'Fmt1' to a 'Fmt'.+{-# INLINE apply #-}+apply :: Fmt1 m s m -> Fmt m s a -> Fmt m s a+apply (Fmt f) (Fmt a) = Fmt (a . f)++-- | Indexed bind.+{-# INLINE bind #-}+bind :: Fmt m a1 b -> (m -> Fmt m a2 a1) -> Fmt m a2 b+bind m f = Fmt $ \k -> unFmt m (\a -> unFmt (f a) k)++-- | Concatenate a collection of formatters.+{-# INLINE cat #-}+cat :: (Monoid m, Foldable f) => f (Fmt m a a) -> Fmt m a a+cat = foldr (%) C.id++-- | Map over the the formatting @Monoid@.+{-# INLINE refmt #-}+refmt :: (m1 -> m2) -> Fmt m1 a b -> Fmt m2 a b+refmt m12 (Fmt f) = Fmt $ \a -> f (a . m12)++{- | Replace one occurance of a search term.++ > replace1 "bar" "foo" "foobarbaz"+ "foofoobaz"+-}+{-# INLINE replace1 #-}+replace1 :: ByteString -> Fmt LogStr a a -> Fmt LogStr a b -> Fmt LogStr a b+replace1 x y =+    splitWith (B.breakSubstring x) $ \l r0 ->+        case B.stripPrefix x r0 of+            Nothing -> logFmt l+            Just r -> cat [logFmt l, y, logFmt r]++{-# INLINE splitWith #-}+splitWith ::+    (ByteString -> (ByteString, ByteString)) -> -- Splitter+    (ByteString -> ByteString -> Fmt LogStr a2 a1) -> -- Joiner+    Fmt LogStr a1 b ->+    Fmt LogStr a2 b+splitWith break join = flip bind $ uncurry join . break . fromLogStr++-- Fmt1++-------------------------++{- | A unary higher-order formatter.++ @ 'Fmt1' m s a ~ (m -> s) -> a -> s @+-}+type Fmt1 m s a = Fmt m s (a -> s)++{- | A binary higher-order formatter.++ @ 'Fmt2' m s a b ~ (m -> s) -> a -> b -> s @+-}+type Fmt2 m s a b = Fmt m s (a -> b -> s)++{- | A ternary higher-order formatter.++ @ 'Fmt3' m s a b c ~ (m -> s) -> a -> b -> c -> s @+-}+type Fmt3 m s a b c = Fmt m s (a -> b -> c -> s)++{- | Format a value of type @a@ using a function of type @a -> m@.++ @ 'runFmt' . 'fmt1' :: (a -> m) -> a -> m @+-}+{-# INLINE fmt1 #-}+fmt1 :: (a -> m) -> Fmt1 m s a+fmt1 f = Fmt $ \k -> k . f++{-# INLINE fmt2 #-}+fmt2 :: (a -> b -> m) -> Fmt2 m s a b+fmt2 f = Fmt $ \k -> fmap k . f++{-# INLINE fmt1_ #-}+fmt1_ :: Fmt m a a -> Fmt1 m a b+fmt1_ = lmap const . closed++{-# INLINE fmt2_ #-}+fmt2_ :: Fmt m a a -> Fmt2 m a b c+fmt2_ = lmap (const . const) . (closed . closed)++-- | Concatenate two formatters, applying both to the same input.+infixr 6 .%++{-# INLINE (.%) #-}+(.%) :: Semigroup m => Fmt1 m s a -> Fmt1 m s a -> Fmt1 m s a+f .% g =+    Fmt+        ( \k a ->+            unFmt f (\b1 -> unFmt g (\b2 -> k (b1 <> b2)) a) a+        )++{- | Format each value in a list and concatenate them all:++ >>> runFmt (cat1 (s % " ")) ["one", "two", "three"]+ "one two three "+-}+{-# INLINE cat1 #-}+cat1 :: (Monoid m, Foldable f) => Fmt1 m m a -> Fmt1 m s (f a)+cat1 f = fmt1 $ foldMap (runFmt f)++{- | Use the given text-joining function to join together the individually rendered items of a list.++ >>> runLogFmt (cat1With (mconcat . reverse) d) [123, 456, 789]+ "789456123"++ @+ 'cat1With' 'L.unlines' :: 'Foldable' f => 'Fmt1' 'LogStr' 'String' a -> 'Fmt1' 'LogStr' s (f a)+ 'cat1With' 'T.unlines' :: 'Foldable' f => 'Fmt1' 'LogStr' 'T.Text' a -> 'Fmt1' 'LogStr' s (f a)+ 'cat1With' 'B.unlines' :: 'Foldable' f => 'Fmt1' 'LogStr' 'B.ByteString' a -> 'Fmt1' 'LogStr' s (f a)+ 'cat1With' '$' 'L.intercalate' " " :: 'Foldable' f => 'Fmt1' 'LogStr' 'String' a -> 'Fmt1' 'LogStr' s (f a)+ 'cat1With' '$' 'T.intercalate' " " :: 'Foldable' f => 'Fmt1' 'LogStr' 'T.Text' a -> 'Fmt1' 'LogStr' s (f a)+ 'cat1With' '$' 'B.intercalate' " " :: 'Foldable' f => 'Fmt1' 'LogStr' 'B.ByteString' a -> 'Fmt1' 'LogStr' s (f a)+ @+-}+{-# INLINEABLE cat1With #-}+cat1With ::+    (Foldable f, ToLogStr str, IsString str) =>+    ([str] -> str) ->+    Fmt1 LogStr str a ->+    Fmt1 LogStr s (f a)+cat1With join f = fmt1 $ toLogStr . join . fmap (runLogFmt f) . toList+{-# SPECIALIZE cat1With :: Foldable f => ([LogStr] -> LogStr) -> Fmt1 LogStr LogStr a -> Fmt1 LogStr s (f a) #-}+{-# SPECIALIZE cat1With :: Foldable f => ([Builder] -> Builder) -> Fmt1 LogStr Builder a -> Fmt1 LogStr s (f a) #-}+{-# SPECIALIZE cat1With :: Foldable f => ([ByteString] -> ByteString) -> Fmt1 LogStr ByteString a -> Fmt1 LogStr s (f a) #-}+{-# SPECIALIZE cat1With :: Foldable f => ([BL.ByteString] -> BL.ByteString) -> Fmt1 LogStr BL.ByteString a -> Fmt1 LogStr s (f a) #-}++{- | Turn a text-splitting function into a formatting combinator.++ @+  'split1With' 'hsep' :: ('Traversable' f, 'ToLogStr' msg) => ('ByteString' -> f msg) -> 'Fmt' 'LogStr' s a -> 'Fmt' 'LogStr' s a+  'split1With' 'vsep' :: ('Traversable' f, 'ToLogStr' msg) => ('ByteString' -> f msg) -> 'Fmt' 'LogStr' s a -> 'Fmt' 'LogStr' s a+  'split1With' 'list1' :: ('Traversable' f, 'ToLogStr' msg) => ('ByteString' -> f msg) -> 'Fmt' 'LogStr' s a -> 'Fmt' 'LogStr' s a+ @+ >>> commas = reverse . fmap BL.reverse . BL.chunksOf 3 . BL.reverse+ >>> dollars = prefix "$" . split1With commas (intercalate ",") . reversed+ >>> runLogFmt (dollars d) 1234567890+ "$1,234,567,890"+ >>> printf (split1With (BL.splitOn ",") vsep t) "one,two,three"+ one+ two+ three+ >>> printf (split1With (BL.splitOn ",") (indentEach 4) t) "one,two,three"+     one+     two+     three+-}+{-# INLINEABLE split1With #-}+split1With ::+    (Traversable f, ToLogStr str) =>+    (Fmt1 m s_ m -> Fmt1 m m (f LogStr)) ->+    (ByteString -> f str) ->+    Fmt LogStr s a ->+    Fmt m s a+split1With lf split (Fmt g) = Fmt (g . (. runFmt (lf $ fmt1 id) . fmap toLogStr . split . fromLogStr))++-- Html++-------------------------++{- | Format HTML++  For example:++  @+  contact :: 'Html' 'LogStr'+  contact = 'Data.Fmt.Html.p' "You can reach me at" '%' 'Data.Fmt.Html.ul' . 'spr' . 'Data.Fmt.Html.li' $ do+        c1 <- 'Data.Fmt.Html.a' '!' 'href' @String "https://example.com" $ "Website"+        c2 <- 'Data.Fmt.Html.a' '!' 'href' @String "mailto:cmk@example.com" $ "Email"+        'pure' $ c1 '<>' c2+  @+  +  generates the following output:++  > "<p>You can reach me at</p><ul><li><a href=\"https://foo.com\">Web</a></li><li><a href=\"mailto:cmk@foo.com\">Email</a></li></ul>"+-}+type Html a = Fmt LogStr a a++toHtml :: ToLogStr s => s -> Html a+toHtml = logFmt++comment :: ToLogStr s => s -> Html a+comment = enclose "<!-- " " -->" . toHtml++-- | Type for an attribute.+newtype Attr = Attr (forall a. Html a -> Html a)++instance Semigroup Attr where+    Attr f <> Attr g = Attr (g . f)++instance Monoid Attr where+    mempty = Attr id++{- | Apply an attribute to an HTML tag.++ The interface is similar to < https://hackage.haskell.org/package/blaze-builder >.++ You should not define your own instances of this class.+-}+class Element html where+    {- | Apply an attribute to an element.++         >>> printf $ img ! src "foo.png"+         <img src="foo.png" />++         This can be used on nested elements as well:++         >>> printf $ p ! style "float: right" $ "Hello!"+         <p style="float: right">Hello!</p>+    -}+    (!) :: html -> Attr -> html++instance Element (Html a) where+    h ! (Attr f) = f h+    {-# INLINE (!) #-}++instance Element (Html a -> Html b) where+    h ! f = (! f) . h+    {-# INLINE (!) #-}++{- | Shorthand for setting an attribute depending on a conditional.++ Example:++ > p !? (isBig, A.class "big") $ "Hello"++ Gives the same result as:++ > (if isBig then p ! A.class "big" else p) "Hello"+-}+(!?) :: Element html => html -> (Bool, Attr) -> html+(!?) h (c, a) = if c then h ! a else h++-- Formatting++-------------------------++{- | Format each value in a list with spaces in between:++ >>> runLogFmt (hsep d) [1, 2, 3]+ "1 2 3"+-}+hsep :: Foldable f => Fmt1 LogStr ByteString a -> Fmt1 LogStr s (f a)+hsep = cat1With $ B.intercalate " "+{-# INLINE hsep #-}++{- | Format each value in a list, placing each on its own line:++ >>> printf (vsep c) ['a'..'c']+ a+ b+ c+-}+vsep :: Foldable f => Fmt1 LogStr ByteString a -> Fmt1 LogStr s (f a)+vsep = cat1With B.unlines+{-# INLINE vsep #-}++{- | Format a list of items, placing one per line, indent by the given number of spaces.++ @ 'indentEach' n = 'Test.Contra.Type.Format.vsep' . 'indent' n @++ >>> printf (split1With BL.lines (indentList 2) t) "one\ntwo\nthree"+   one+   two+   three+ >>> printf ("The lucky numbers are:\n" % indentList 2 d) [7, 13, 1, 42]+ The lucky numbers are:+   7+   13+   1+   42+-}+hang :: Foldable f => Int -> Fmt1 LogStr ByteString a -> Fmt1 LogStr s (f a)+hang n = vsep . indent n+{-# INLINE hang #-}++{- | Insert the given number of spaces at the start of the rendered text:++ >>> runFmt (indent 4 d) 7+ "    7"++ Note that this only indents the first line of a multi-line string.+ To indent all lines see 'reindent'.+-}+indent :: (IsString m, Semigroup m) => Int -> Fmt m a b -> Fmt m a b+indent n = prefix $ fromString $ replicate n ' '+{-# INLINEABLE indent #-}++{- | Add the given prefix to the formatted item:++ >>> runLogFmt ("The answer is: " % prefix "wait for it... " d) 42+ "The answer is: wait for it... 42"++ >>> printf (vsep (indent 4 (prefix "- " d))) [1, 2, 3]+     - 1+     - 2+     - 3+-}+prefix :: Semigroup m => m -> Fmt m a b -> Fmt m a b+prefix s f = fmt s % f+{-# INLINE prefix #-}++-- | Add the given suffix to the formatted item.+suffix :: Semigroup m => m -> Fmt m a b -> Fmt m a b+suffix s f = f % fmt s+{-# INLINE suffix #-}++{- | Enclose the output string with the given strings:++ >>> runFmt (parens $ enclose v s ", ") 1 "two"+ "(1, two)"+ >>> runFmt (enclose (fmt "<!--") (fmt "-->") s) "an html comment"+ "<!--an html comment-->"+-}+enclose :: Semigroup m => Fmt m b2 c -> Fmt m a b1 -> Fmt m b1 b2 -> Fmt m a c+enclose pre suf f = pre % f % suf+{-# INLINE enclose #-}++-- @ 'tuple' 'd' 'd' :: 'LogFmt2' a 'Int' @+--+-- >>> runFmt (tuple d t) 1 "two"+-- "(1, two)"+tuple :: (Semigroup m, IsString m) => Fmt m b c -> Fmt m a b -> Fmt m a c+tuple f1 f2 = parens $ enclose f1 f2 ", "++{- | Add double quotes around the formatted item:++ Use this to escape a string:++ >>> runFmt ("He said it was based on " % quotes t' % ".") "science"+ He said it was based on "science".+-}+quotes :: (Semigroup m, IsString m) => Fmt m a b -> Fmt m a b+quotes = enclose "\"" "\""+{-# INLINE quotes #-}++{- | Add single quotes around the formatted item:++ >>> let obj = Just Nothing in format ("The object is: " % quotes' shown % ".") obj+ "The object is: 'Just Nothing'."+-}+quotes' :: (Semigroup m, IsString m) => Fmt m a b -> Fmt m a b+quotes' = enclose "'" "'"+{-# INLINE quotes' #-}++{- | Add parentheses around the formatted item:++ >>> runFmt ("We found " % parens d % " discrepancies.") 17+ "We found (17) discrepancies."++ >>> printf (get 5 (list1 (parens d))) [1..]+ [(1), (2), (3), (4), (5)]+-}+parens :: (Semigroup m, IsString m) => Fmt m a b -> Fmt m a b+parens = enclose "(" ")"+{-# INLINE parens #-}++{- | Add braces around the formatted item:++ >>> runFmt ("\\begin" % braces t) "section"+ "\\begin{section}"+-}+braces :: (Semigroup m, IsString m) => Fmt m a b -> Fmt m a b+braces = enclose "{" "}"+{-# INLINE braces #-}++{- | Add square brackets around the formatted item:++ >>> runFmt (brackets d) 7+ "[7]"+-}+brackets :: (Semigroup m, IsString m) => Fmt m a b -> Fmt m a b+brackets = enclose "[" "]"+{-# INLINE brackets #-}++{- | Add backticks around the formatted item:++ >>> runLogFmt ("Be sure to run " % backticks builder % " as root.") ":(){:|:&};:"+ "Be sure to run `:(){:|:&};:` as root."+-}+backticks :: (Semigroup m, IsString m) => Fmt m a b -> Fmt m a b+backticks = enclose "`" "`"+{-# INLINE backticks #-}++-- Collections++-------------------------++{- | Render the value in a Left with the given formatter, rendering a Right as an empty string:++ >>> runLogFmt (left1 text) (Left "bingo")+ "bingo"++ >>> runLogFmt (left1 text) (Right 16)+ ""+-}+left1 :: IsString m => Fmt1 m m a -> Fmt1 m s (Either a b)+left1 f = either1 f (fmt1 $ const "")+{-# INLINE left1 #-}++{- | Render the value in a Right with the given formatter, rendering a Left as an empty string:++ >>> runLogFmt (right1 text) (Left 16)+ ""++ >>> runLogFmt (right1 text) (Right "bingo")+ "bingo"+-}+right1 :: IsString m => Fmt1 m m b -> Fmt1 m s (Either a b)+right1 = either1 (fmt1 $ const "")+{-# INLINE right1 #-}++{- | Render the value in an Either:++ >>> runLogFmt (either1 text int) (Left "Error!"+ "Error!"++ >>> runLogFmt (either1 text int) (Right 69)+ "69"+-}+either1 :: Fmt1 m m a -> Fmt1 m m b -> Fmt1 m s (Either a b)+either1 l r = fmt1 $ either (runFmt l) (runFmt r)+{-# INLINE either1 #-}++{- | Render a Maybe value either as a default (if Nothing) or using the given formatter:++ >>> runLogFmt (maybe1 "Goodbye" text) Nothing+ "Goodbye"++ >>> runLogFmt (maybe1 "Goodbye" text) (Just "Hello")+ "Hello"+-}+maybe1 :: m -> Fmt1 m m a -> Fmt1 m s (Maybe a)+maybe1 def f = fmt1 $ maybe def (runFmt f)+{-# INLINE maybe1 #-}++{- | Add square brackets around the Foldable (e.g. a list), and separate each formatted item with a comma and space.++ >>> runLogFmt (list1 s) ["one", "two", "three"]+ "[one, two, three]"+ >>> printf (quotes $ list1 d) [1,2,3]+ ["1", "2", "3"]+ >>> printf (quotes $ list1 s) ["one", "two", "three"]+ ["one", "two", "three"]+-}+list1 :: Foldable f => Fmt1 LogStr ByteString a -> Fmt1 LogStr s (f a)+list1 = cat1With (B.intercalate ", ") . brackets+{-# INLINE list1 #-}++{- | A JSON-style formatter for lists.++ >>> printf jsonList [1,2,3]+ [+   1+ , 2+ , 3+ ]++ Like 'yamlListF', it handles multiline elements well:++ >>> fmt $ jsonListF ["hello\nworld", "foo\nbar\nquix"]+ [+   hello+   world+ , foo+   bar+   quix+ ]+-}+{-# INLINE jsonList #-}+jsonList :: (Foldable f, ToLogStr a) => Fmt1 LogStr s (f a)+jsonList = fmt1 f+  where+    f xs+        | null items = "[]\n"+        | otherwise = "[\n" <> mconcat items <> "]\n"+      where+        items = zipWith buildItem (True : repeat False) (toList xs)+        -- Item builder+        --buildItem :: Bool -> a -> B++        buildItem isFirst x =+            case map toLogStr (B.lines (fromLogStr (toLogStr x))) of+                []+                    | isFirst -> "\n"+                    | otherwise -> ",\n"+                (h : t) ->+                    mconcat . map (<> "\n") $+                        if isFirst+                            then "  " <> h : fmap ("  " <>) t+                            else ", " <> h : fmap ("  " <>) t++{- | A multiline formatter for lists.++  >>> printf (yamlList d) [1,2,3]+  - 1+  - 2+  - 3++  Multi-line elements are indented correctly:++  >>> printf (yamlList s) ["hello\nworld", "foo\nbar\nquix"]+  - hello+    world+  - foo+    bar+    quix+-}+{-# INLINE yamlList #-}+yamlList :: (Foldable f, ToLogStr a) => Fmt1 LogStr s (f a)+yamlList = fmt1 f+  where+    f xs = if null items then "[]\n" else mconcat items+      where+        bullet = "-"+        spaces = "  "+        newline = "\n"+        items = map buildItem (toList xs)+        buildItem x = case B.lines (fromLogStr (toLogStr x)) of+            [] -> bullet <> newline+            (l : ls) ->+                bullet <> " " <> toLogStr l <> newline+                    <> mconcat [spaces <> toLogStr s <> newline | s <- ls]++{- | A JSON-like map formatter; works for Map, HashMap, etc, and lists of pairs.++>>> fmt $ jsonMapF [("Odds", jsonListF [1,3]), ("Evens", jsonListF [2,4])]+{+  Odds:+    [+      1+    , 3+    ]+, Evens:+    [+      2+    , 4+    ]+}+-}+{-# INLINE jsonMap #-}+jsonMap :: (ToLogStr k, IsList map, Item map ~ (k, ByteString)) => Fmt1 LogStr s map+jsonMap = fmt1 f+  where+    f xs+        | null items = "{}\n"+        | otherwise = "{\n" <> mconcat items <> "}\n"+      where+        items = zipWith buildItem (True : repeat False) (IsList.toList xs)+        -- Item builder+        --buildItem :: Bool -> (k, v) -> B+        buildItem isFirst (k, v) = do+            let kb = (if isFirst then "  " else ", ") <> toLogStr k+            case map toLogStr (B.lines v) of+                [] -> kb <> ":\n"+                [l] -> kb <> ": " <> l <> "\n"+                ls ->+                    kb <> ":\n"+                        <> mconcat ["    " <> s <> "\n" | s <- ls]++--  | A YAML-like map formatter:+--+-- >>> BL.putStrLn $ BL.toLazyByteString $ yamlMapF id id [("Odds", yamlListF (BL.fromString . show) "-" [1,3]), ("Evens", yamlListF (BL.fromString . show) "-" [2,4])]+-- Odds:+--   - 1+--   - 3+-- Evens:+--   - 2+--   - 4+{-# INLINE yamlMap #-}+yamlMap :: (ToLogStr k, ToLogStr v, IsList map, Item map ~ (k, v)) => Fmt1 LogStr s map+yamlMap = fmt1 f+  where+    f xs+        | null items = "{}\n"+        | otherwise = mconcat items+      where+        items = map (\(k, v) -> nameF (toLogStr k) (toLogStr v)) (IsList.toList xs)++nameF :: LogStr -> LogStr -> LogStr+nameF k v = case B.lines (fromLogStr v) of+    [] -> k <> ":\n"+    [l] -> k <> ": " <> toLogStr l <> "\n"+    ls ->+        k <> ":\n"+            <> mconcat ["  " <> toLogStr s <> "\n" | s <- ls]
+ src/Data/Fmt/Ansi.hs view
@@ -0,0 +1,102 @@+module Data.Fmt.Ansi (+    -- * Ansi terminal codes+    code,+    codes,+    erase,+    reset,+    shift,+    scroll,++    -- ** Emphasis+    blink,+    bold,+    faint,+    italic,+    underline,++    -- ** Color+    dull,+    vivid,+    layer,+    palette,+    Palette,+    XColor,+    Color (..),+    ConsoleLayer (..),+) where++import Data.Fmt+import Data.Word+import System.Console.ANSI.Codes+import System.Console.ANSI.Types++-- Ansi terminal formatters++-------------------------++code :: (Semigroup m, IsString m) => SGR -> Fmt m s a -> Fmt m s a+code = codes . pure++-- | Wrap content with escape sequence to set and reset color of normal intensity.+codes :: (Semigroup m, IsString m) => [SGR] -> Fmt m s a -> Fmt m s a+codes sgr x = enclose before after x+  where+    before = fromString $ setSGRCode sgr+    after = fromString $ setSGRCode [Reset]++erase :: (Semigroup m, IsString m) => Ordering -> Fmt m s a -> Fmt m s a+erase LT = suffix $ fromString clearFromCursorToLineBeginningCode+erase EQ = suffix $ fromString clearLineCode+erase GT = suffix $ fromString clearFromCursorToLineEndCode++reset :: (Semigroup m, IsString m) => Fmt m s a -> Fmt m s a+reset = prefix $ fromString $ setSGRCode [Reset]++shift :: (Semigroup m, IsString m) => Either Int Int -> Fmt m s a -> Fmt m s a+shift = prefix . fromString . either cursorBackwardCode cursorForwardCode++scroll :: (Semigroup m, IsString m) => Either Int Int -> Fmt m s a -> Fmt m s a+scroll = prefix . fromString . either scrollPageUpCode scrollPageDownCode++-- Emphasis++-------------------------++blink :: (Semigroup m, IsString m) => Fmt m s a -> Fmt m s a+blink = code $ SetBlinkSpeed SlowBlink++bold :: (Semigroup m, IsString m) => Fmt m s a -> Fmt m s a+bold = code $ SetConsoleIntensity BoldIntensity++italic :: (Semigroup m, IsString m) => Fmt m s a -> Fmt m s a+italic = code $ SetItalicized True++underline :: (Semigroup m, IsString m) => Fmt m s a -> Fmt m s a+underline = code $ SetUnderlining SingleUnderline++faint :: (Semigroup m, IsString m) => Fmt m s a -> Fmt m s a+faint = code $ SetConsoleIntensity FaintIntensity++-- Color++-------------------------++-- | The xterm < https://en.wikipedia.org/wiki/8-bit_color 8 bit > color encoding.+type XColor = Word8++-- | A simple palette consisting of a foreground and background color.+type Palette = (XColor, XColor)++dull :: (Semigroup m, IsString m) => Color -> ConsoleLayer -> Fmt m s a -> Fmt m s a+dull = layer . xtermSystem Dull++vivid :: (Semigroup m, IsString m) => Color -> ConsoleLayer -> Fmt m s a -> Fmt m s a+vivid = layer . xtermSystem Vivid++--vivid col lay = code $ SetColor lay Vivid col++layer :: (Semigroup m, IsString m) => XColor -> ConsoleLayer -> Fmt m s a -> Fmt m s a+layer pal lay = code $ SetPaletteColor lay pal++palette :: (Semigroup m, IsString m) => Palette -> Fmt m s a -> Fmt m s a+palette (fg, bg) = codes [SetPaletteColor Foreground fg, SetPaletteColor Background bg]
+ src/Data/Fmt/Attr.hs view
@@ -0,0 +1,3414 @@+{-# LANGUAGE OverloadedStrings #-}++{- | Html5 formatting.++ The API is similar to < https://hackage.haskell.org/package/blaze-html >.+-}+module Data.Fmt.Attr (+    -- * Html+    Html,+    Attr,+    toHtml,+    comment,+    Element (..),+    (!?),++    -- * Attributes+    accept,+    acceptCharset,+    accesskey,+    action,+    alt,+    async,+    autocomplete,+    autofocus,+    autoplay,+    challenge,+    charset,+    checked,+    cite,+    class_,+    cols,+    colspan,+    content,+    contenteditable,+    contextmenu,+    controls,+    coords,+    data_,+    datetime,+    defer,+    dir,+    disabled,+    draggable,+    enctype,+    for,+    form,+    formaction,+    formenctype,+    formmethod,+    formnovalidate,+    formtarget,+    headers,+    height,+    hidden,+    high,+    href,+    hreflang,+    httpEquiv,+    icon,+    id,+    ismap,+    item,+    itemprop,+    itemscope,+    itemtype,+    keytype,+    label,+    lang,+    list,+    loop,+    low,+    manifest,+    max,+    maxlength,+    media,+    method,+    min,+    multiple,+    name,+    novalidate,+    onbeforeonload,+    onbeforeprint,+    onblur,+    oncanplay,+    oncanplaythrough,+    onchange,+    onclick,+    oncontextmenu,+    ondblclick,+    ondrag,+    ondragend,+    ondragenter,+    ondragleave,+    ondragover,+    ondragstart,+    ondrop,+    ondurationchange,+    onemptied,+    onended,+    onerror,+    onfocus,+    onformchange,+    onforminput,+    onhaschange,+    oninput,+    oninvalid,+    onkeydown,+    onkeyup,+    onload,+    onloadeddata,+    onloadedmetadata,+    onloadstart,+    onmessage,+    onmousedown,+    onmousemove,+    onmouseout,+    onmouseover,+    onmouseup,+    onmousewheel,+    ononline,+    onpagehide,+    onpageshow,+    onpause,+    onplay,+    onplaying,+    onprogress,+    onpropstate,+    onratechange,+    onreadystatechange,+    onredo,+    onresize,+    onscroll,+    onseeked,+    onseeking,+    onselect,+    onstalled,+    onstorage,+    onsubmit,+    onsuspend,+    ontimeupdate,+    onundo,+    onunload,+    onvolumechange,+    onwaiting,+    open,+    optimum,+    pattern,+    ping,+    placeholder,+    preload,+    pubdate,+    radiogroup,+    readonly,+    rel,+    required,+    reversed,+    role,+    rows,+    rowspan,+    sandbox,+    scope,+    scoped,+    seamless,+    selected,+    shape,+    size,+    sizes,+    span,+    spellcheck,+    src,+    srcdoc,+    start,+    step,+    style,+    subject,+    summary,+    tabindex,+    target,+    title,+    type_,+    usemap,+    value,+    width,+    wrap,+    xmlns,+) where++import qualified Data.ByteString.Char8 as B+import Data.Fmt+import Prelude (Eq (..), Maybe (..), Monoid (..), ($), (||))++attr :: ToLogStr s => LogStr -> s -> Attr+attr k v = Attr $ splitWith f g+  where+    f = B.break $ \c -> c == '/' || c == '>'+    g l r0 = case B.uncons r0 of+        Just ('/', r) -> toHtml l % fmt k % "=" % quotes (toHtml v) % fmt " /" % toHtml r+        Just ('>', r) -> toHtml l % " " % fmt k % "=" % quotes (toHtml v) % fmt ">" % toHtml r+        _ -> fmt mempty++-- Attributes++-------------------------++{- | Combinator for the @accept@ attribute.++ Example:++ > div ! accept "bar" $ "Hello."++ Result:++ > <div accept="bar">Hello.</div>+-}+accept ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+accept = attr "accept"+{-# INLINE accept #-}++{- | Combinator for the @accept-charset@ attribute.++ Example:++ > div ! acceptCharset "bar" $ "Hello."++ Result:++ > <div accept-charset="bar">Hello.</div>+-}+acceptCharset ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+acceptCharset = attr "accept-charset"+{-# INLINE acceptCharset #-}++{- | Combinator for the @accesskey@ attribute.++ Example:++ > div ! accesskey "bar" $ "Hello."++ Result:++ > <div accesskey="bar">Hello.</div>+-}+accesskey ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+accesskey = attr "accesskey"+{-# INLINE accesskey #-}++{- | Combinator for the @action@ attribute.++ Example:++ > div ! action "bar" $ "Hello."++ Result:++ > <div action="bar">Hello.</div>+-}+action ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+action = attr "action"+{-# INLINE action #-}++{- | Combinator for the @alt@ attribute.++ Example:++ > div ! alt "bar" $ "Hello."++ Result:++ > <div alt="bar">Hello.</div>+-}+alt ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+alt = attr "alt"+{-# INLINE alt #-}++{- | Combinator for the @async@ attribute.++ Example:++ > div ! async "bar" $ "Hello."++ Result:++ > <div async="bar">Hello.</div>+-}+async ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+async = attr "async"+{-# INLINE async #-}++{- | Combinator for the @autocomplete@ attribute.++ Example:++ > div ! autocomplete "bar" $ "Hello."++ Result:++ > <div autocomplete="bar">Hello.</div>+-}+autocomplete ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+autocomplete = attr "autocomplete"+{-# INLINE autocomplete #-}++{- | Combinator for the @autofocus@ attribute.++ Example:++ > div ! autofocus "bar" $ "Hello."++ Result:++ > <div autofocus="bar">Hello.</div>+-}+autofocus ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+autofocus = attr "autofocus"+{-# INLINE autofocus #-}++{- | Combinator for the @autoplay@ attribute.++ Example:++ > div ! autoplay "bar" $ "Hello."++ Result:++ > <div autoplay="bar">Hello.</div>+-}+autoplay ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+autoplay = attr "autoplay"+{-# INLINE autoplay #-}++{- | Combinator for the @challenge@ attribute.++ Example:++ > div ! challenge "bar" $ "Hello."++ Result:++ > <div challenge="bar">Hello.</div>+-}+challenge ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+challenge = attr "challenge"+{-# INLINE challenge #-}++{- | Combinator for the @charset@ attribute.++ Example:++ > div ! charset "bar" $ "Hello."++ Result:++ > <div charset="bar">Hello.</div>+-}+charset ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+charset = attr "charset"+{-# INLINE charset #-}++{- | Combinator for the @checked@ attribute.++ Example:++ > div ! checked "bar" $ "Hello."++ Result:++ > <div checked="bar">Hello.</div>+-}+checked ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+checked = attr "checked"+{-# INLINE checked #-}++{- | Combinator for the @cite@ attribute.++ Example:++ > div ! cite "bar" $ "Hello."++ Result:++ > <div cite="bar">Hello.</div>+-}+cite ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+cite = attr "cite"+{-# INLINE cite #-}++{- | Combinator for the @class@ attribute.++ Example:++ > div ! class_ "bar" $ "Hello."++ Result:++ > <div class="bar">Hello.</div>+-}+class_ ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+class_ = attr "class"+{-# INLINE class_ #-}++{- | Combinator for the @cols@ attribute.++ Example:++ > div ! cols "bar" $ "Hello."++ Result:++ > <div cols="bar">Hello.</div>+-}+cols ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+cols = attr "cols"+{-# INLINE cols #-}++{- | Combinator for the @colspan@ attribute.++ Example:++ > div ! colspan "bar" $ "Hello."++ Result:++ > <div colspan="bar">Hello.</div>+-}+colspan ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+colspan = attr "colspan"+{-# INLINE colspan #-}++{- | Combinator for the @content@ attribute.++ Example:++ > div ! content "bar" $ "Hello."++ Result:++ > <div content="bar">Hello.</div>+-}+content ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+content = attr "content"+{-# INLINE content #-}++{- | Combinator for the @contenteditable@ attribute.++ Example:++ > div ! contenteditable "bar" $ "Hello."++ Result:++ > <div contenteditable="bar">Hello.</div>+-}+contenteditable ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+contenteditable = attr "contenteditable"+{-# INLINE contenteditable #-}++{- | Combinator for the @contextmenu@ attribute.++ Example:++ > div ! contextmenu "bar" $ "Hello."++ Result:++ > <div contextmenu="bar">Hello.</div>+-}+contextmenu ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+contextmenu = attr "contextmenu"+{-# INLINE contextmenu #-}++{- | Combinator for the @controls@ attribute.++ Example:++ > div ! controls "bar" $ "Hello."++ Result:++ > <div controls="bar">Hello.</div>+-}+controls ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+controls = attr "controls"+{-# INLINE controls #-}++{- | Combinator for the @coords@ attribute.++ Example:++ > div ! coords "bar" $ "Hello."++ Result:++ > <div coords="bar">Hello.</div>+-}+coords ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+coords = attr "coords"+{-# INLINE coords #-}++{- | Combinator for the @data@ attribute.++ Example:++ > div ! data_ "bar" $ "Hello."++ Result:++ > <div data="bar">Hello.</div>+-}+data_ ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+data_ = attr "data"+{-# INLINE data_ #-}++{- | Combinator for the @datetime@ attribute.++ Example:++ > div ! datetime "bar" $ "Hello."++ Result:++ > <div datetime="bar">Hello.</div>+-}+datetime ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+datetime = attr "datetime"+{-# INLINE datetime #-}++{- | Combinator for the @defer@ attribute.++ Example:++ > div ! defer "bar" $ "Hello."++ Result:++ > <div defer="bar">Hello.</div>+-}+defer ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+defer = attr "defer"+{-# INLINE defer #-}++{- | Combinator for the @dir@ attribute.++ Example:++ > div ! dir "bar" $ "Hello."++ Result:++ > <div dir="bar">Hello.</div>+-}+dir ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+dir = attr "dir"+{-# INLINE dir #-}++{- | Combinator for the @disabled@ attribute.++ Example:++ > div ! disabled "bar" $ "Hello."++ Result:++ > <div disabled="bar">Hello.</div>+-}+disabled ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+disabled = attr "disabled"+{-# INLINE disabled #-}++{- | Combinator for the @draggable@ attribute.++ Example:++ > div ! draggable "bar" $ "Hello."++ Result:++ > <div draggable="bar">Hello.</div>+-}+draggable ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+draggable = attr "draggable"+{-# INLINE draggable #-}++{- | Combinator for the @enctype@ attribute.++ Example:++ > div ! enctype "bar" $ "Hello."++ Result:++ > <div enctype="bar">Hello.</div>+-}+enctype ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+enctype = attr "enctype"+{-# INLINE enctype #-}++{- | Combinator for the @for@ attribute.++ Example:++ > div ! for "bar" $ "Hello."++ Result:++ > <div for="bar">Hello.</div>+-}+for ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+for = attr "for"+{-# INLINE for #-}++{- | Combinator for the @form@ attribute.++ Example:++ > div ! form "bar" $ "Hello."++ Result:++ > <div form="bar">Hello.</div>+-}+form ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+form = attr "form"+{-# INLINE form #-}++{- | Combinator for the @formaction@ attribute.++ Example:++ > div ! formaction "bar" $ "Hello."++ Result:++ > <div formaction="bar">Hello.</div>+-}+formaction ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+formaction = attr "formaction"+{-# INLINE formaction #-}++{- | Combinator for the @formenctype@ attribute.++ Example:++ > div ! formenctype "bar" $ "Hello."++ Result:++ > <div formenctype="bar">Hello.</div>+-}+formenctype ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+formenctype = attr "formenctype"+{-# INLINE formenctype #-}++{- | Combinator for the @formmethod@ attribute.++ Example:++ > div ! formmethod "bar" $ "Hello."++ Result:++ > <div formmethod="bar">Hello.</div>+-}+formmethod ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+formmethod = attr "formmethod"+{-# INLINE formmethod #-}++{- | Combinator for the @formnovalidate@ attribute.++ Example:++ > div ! formnovalidate "bar" $ "Hello."++ Result:++ > <div formnovalidate="bar">Hello.</div>+-}+formnovalidate ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+formnovalidate = attr "formnovalidate"+{-# INLINE formnovalidate #-}++{- | Combinator for the @formtarget@ attribute.++ Example:++ > div ! formtarget "bar" $ "Hello."++ Result:++ > <div formtarget="bar">Hello.</div>+-}+formtarget ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+formtarget = attr "formtarget"+{-# INLINE formtarget #-}++{- | Combinator for the @headers@ attribute.++ Example:++ > div ! headers "bar" $ "Hello."++ Result:++ > <div headers="bar">Hello.</div>+-}+headers ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+headers = attr "headers"+{-# INLINE headers #-}++{- | Combinator for the @height@ attribute.++ Example:++ > div ! height "bar" $ "Hello."++ Result:++ > <div height="bar">Hello.</div>+-}+height ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+height = attr "height"+{-# INLINE height #-}++{- | Combinator for the @hidden@ attribute.++ Example:++ > div ! hidden "bar" $ "Hello."++ Result:++ > <div hidden="bar">Hello.</div>+-}+hidden ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+hidden = attr "hidden"+{-# INLINE hidden #-}++{- | Combinator for the @high@ attribute.++ Example:++ > div ! high "bar" $ "Hello."++ Result:++ > <div high="bar">Hello.</div>+-}+high ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+high = attr "high"+{-# INLINE high #-}++{- | Combinator for the @href@ attribute.++ Example:++ > div ! href "bar" $ "Hello."++ Result:++ > <div href="bar">Hello.</div>+-}+href ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+href = attr "href"+{-# INLINE href #-}++{- | Combinator for the @hreflang@ attribute.++ Example:++ > div ! hreflang "bar" $ "Hello."++ Result:++ > <div hreflang="bar">Hello.</div>+-}+hreflang ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+hreflang = attr "hreflang"+{-# INLINE hreflang #-}++{- | Combinator for the @http-equiv@ attribute.++ Example:++ > div ! httpEquiv "bar" $ "Hello."++ Result:++ > <div http-equiv="bar">Hello.</div>+-}+httpEquiv ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+httpEquiv = attr "http-equiv"+{-# INLINE httpEquiv #-}++{- | Combinator for the @icon@ attribute.++ Example:++ > div ! icon "bar" $ "Hello."++ Result:++ > <div icon="bar">Hello.</div>+-}+icon ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+icon = attr "icon"+{-# INLINE icon #-}++{- | Combinator for the @id@ attribute.++ Example:++ > div ! id "bar" $ "Hello."++ Result:++ > <div id="bar">Hello.</div>+-}+id ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+id = attr "id"+{-# INLINE id #-}++{- | Combinator for the @ismap@ attribute.++ Example:++ > div ! ismap "bar" $ "Hello."++ Result:++ > <div ismap="bar">Hello.</div>+-}+ismap ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ismap = attr "ismap"+{-# INLINE ismap #-}++{- | Combinator for the @item@ attribute.++ Example:++ > div ! item "bar" $ "Hello."++ Result:++ > <div item="bar">Hello.</div>+-}+item ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+item = attr "item"+{-# INLINE item #-}++{- | Combinator for the @itemprop@ attribute.++ Example:++ > div ! itemprop "bar" $ "Hello."++ Result:++ > <div itemprop="bar">Hello.</div>+-}+itemprop ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+itemprop = attr "itemprop"+{-# INLINE itemprop #-}++{- | Combinator for the @itemscope@ attribute.++ Example:++ > div ! itemscope "bar" $ "Hello."++ Result:++ > <div itemscope="bar">Hello.</div>+-}+itemscope ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+itemscope = attr "itemscope"+{-# INLINE itemscope #-}++{- | Combinator for the @itemtype@ attribute.++ Example:++ > div ! itemtype "bar" $ "Hello."++ Result:++ > <div itemtype="bar">Hello.</div>+-}+itemtype ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+itemtype = attr "itemtype"+{-# INLINE itemtype #-}++{- | Combinator for the @keytype@ attribute.++ Example:++ > div ! keytype "bar" $ "Hello."++ Result:++ > <div keytype="bar">Hello.</div>+-}+keytype ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+keytype = attr "keytype"+{-# INLINE keytype #-}++{- | Combinator for the @label@ attribute.++ Example:++ > div ! label "bar" $ "Hello."++ Result:++ > <div label="bar">Hello.</div>+-}+label ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+label = attr "label"+{-# INLINE label #-}++{- | Combinator for the @lang@ attribute.++ Example:++ > div ! lang "bar" $ "Hello."++ Result:++ > <div lang="bar">Hello.</div>+-}+lang ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+lang = attr "lang"+{-# INLINE lang #-}++{- | Combinator for the @list@ attribute.++ Example:++ > div ! list "bar" $ "Hello."++ Result:++ > <div list="bar">Hello.</div>+-}+list ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+list = attr "list"+{-# INLINE list #-}++{- | Combinator for the @loop@ attribute.++ Example:++ > div ! loop "bar" $ "Hello."++ Result:++ > <div loop="bar">Hello.</div>+-}+loop ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+loop = attr "loop"+{-# INLINE loop #-}++{- | Combinator for the @low@ attribute.++ Example:++ > div ! low "bar" $ "Hello."++ Result:++ > <div low="bar">Hello.</div>+-}+low ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+low = attr "low"+{-# INLINE low #-}++{- | Combinator for the @manifest@ attribute.++ Example:++ > div ! manifest "bar" $ "Hello."++ Result:++ > <div manifest="bar">Hello.</div>+-}+manifest ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+manifest = attr "manifest"+{-# INLINE manifest #-}++{- | Combinator for the @max@ attribute.++ Example:++ > div ! max "bar" $ "Hello."++ Result:++ > <div max="bar">Hello.</div>+-}+max ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+max = attr "max"+{-# INLINE max #-}++{- | Combinator for the @maxlength@ attribute.++ Example:++ > div ! maxlength "bar" $ "Hello."++ Result:++ > <div maxlength="bar">Hello.</div>+-}+maxlength ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+maxlength = attr "maxlength"+{-# INLINE maxlength #-}++{- | Combinator for the @media@ attribute.++ Example:++ > div ! media "bar" $ "Hello."++ Result:++ > <div media="bar">Hello.</div>+-}+media ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+media = attr "media"+{-# INLINE media #-}++{- | Combinator for the @method@ attribute.++ Example:++ > div ! method "bar" $ "Hello."++ Result:++ > <div method="bar">Hello.</div>+-}+method ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+method = attr "method"+{-# INLINE method #-}++{- | Combinator for the @min@ attribute.++ Example:++ > div ! min "bar" $ "Hello."++ Result:++ > <div min="bar">Hello.</div>+-}+min ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+min = attr "min"+{-# INLINE min #-}++{- | Combinator for the @multiple@ attribute.++ Example:++ > div ! multiple "bar" $ "Hello."++ Result:++ > <div multiple="bar">Hello.</div>+-}+multiple ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+multiple = attr "multiple"+{-# INLINE multiple #-}++{- | Combinator for the @name@ attribute.++ Example:++ > div ! name "bar" $ "Hello."++ Result:++ > <div name="bar">Hello.</div>+-}+name ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+name = attr "name"+{-# INLINE name #-}++{- | Combinator for the @novalidate@ attribute.++ Example:++ > div ! novalidate "bar" $ "Hello."++ Result:++ > <div novalidate="bar">Hello.</div>+-}+novalidate ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+novalidate = attr "novalidate"+{-# INLINE novalidate #-}++{- | Combinator for the @onbeforeonload@ attribute.++ Example:++ > div ! onbeforeonload "bar" $ "Hello."++ Result:++ > <div onbeforeonload="bar">Hello.</div>+-}+onbeforeonload ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onbeforeonload = attr "onbeforeonload"+{-# INLINE onbeforeonload #-}++{- | Combinator for the @onbeforeprint@ attribute.++ Example:++ > div ! onbeforeprint "bar" $ "Hello."++ Result:++ > <div onbeforeprint="bar">Hello.</div>+-}+onbeforeprint ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onbeforeprint = attr "onbeforeprint"+{-# INLINE onbeforeprint #-}++{- | Combinator for the @onblur@ attribute.++ Example:++ > div ! onblur "bar" $ "Hello."++ Result:++ > <div onblur="bar">Hello.</div>+-}+onblur ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onblur = attr "onblur"+{-# INLINE onblur #-}++{- | Combinator for the @oncanplay@ attribute.++ Example:++ > div ! oncanplay "bar" $ "Hello."++ Result:++ > <div oncanplay="bar">Hello.</div>+-}+oncanplay ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+oncanplay = attr "oncanplay"+{-# INLINE oncanplay #-}++{- | Combinator for the @oncanplaythrough@ attribute.++ Example:++ > div ! oncanplaythrough "bar" $ "Hello."++ Result:++ > <div oncanplaythrough="bar">Hello.</div>+-}+oncanplaythrough ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+oncanplaythrough = attr "oncanplaythrough"+{-# INLINE oncanplaythrough #-}++{- | Combinator for the @onchange@ attribute.++ Example:++ > div ! onchange "bar" $ "Hello."++ Result:++ > <div onchange="bar">Hello.</div>+-}+onchange ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onchange = attr "onchange"+{-# INLINE onchange #-}++{- | Combinator for the @onclick@ attribute.++ Example:++ > div ! onclick "bar" $ "Hello."++ Result:++ > <div onclick="bar">Hello.</div>+-}+onclick ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onclick = attr "onclick"+{-# INLINE onclick #-}++{- | Combinator for the @oncontextmenu@ attribute.++ Example:++ > div ! oncontextmenu "bar" $ "Hello."++ Result:++ > <div oncontextmenu="bar">Hello.</div>+-}+oncontextmenu ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+oncontextmenu = attr "oncontextmenu"+{-# INLINE oncontextmenu #-}++{- | Combinator for the @ondblclick@ attribute.++ Example:++ > div ! ondblclick "bar" $ "Hello."++ Result:++ > <div ondblclick="bar">Hello.</div>+-}+ondblclick ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ondblclick = attr "ondblclick"+{-# INLINE ondblclick #-}++{- | Combinator for the @ondrag@ attribute.++ Example:++ > div ! ondrag "bar" $ "Hello."++ Result:++ > <div ondrag="bar">Hello.</div>+-}+ondrag ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ondrag = attr "ondrag"+{-# INLINE ondrag #-}++{- | Combinator for the @ondragend@ attribute.++ Example:++ > div ! ondragend "bar" $ "Hello."++ Result:++ > <div ondragend="bar">Hello.</div>+-}+ondragend ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ondragend = attr "ondragend"+{-# INLINE ondragend #-}++{- | Combinator for the @ondragenter@ attribute.++ Example:++ > div ! ondragenter "bar" $ "Hello."++ Result:++ > <div ondragenter="bar">Hello.</div>+-}+ondragenter ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ondragenter = attr "ondragenter"+{-# INLINE ondragenter #-}++{- | Combinator for the @ondragleave@ attribute.++ Example:++ > div ! ondragleave "bar" $ "Hello."++ Result:++ > <div ondragleave="bar">Hello.</div>+-}+ondragleave ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ondragleave = attr "ondragleave"+{-# INLINE ondragleave #-}++{- | Combinator for the @ondragover@ attribute.++ Example:++ > div ! ondragover "bar" $ "Hello."++ Result:++ > <div ondragover="bar">Hello.</div>+-}+ondragover ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ondragover = attr "ondragover"+{-# INLINE ondragover #-}++{- | Combinator for the @ondragstart@ attribute.++ Example:++ > div ! ondragstart "bar" $ "Hello."++ Result:++ > <div ondragstart="bar">Hello.</div>+-}+ondragstart ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ondragstart = attr "ondragstart"+{-# INLINE ondragstart #-}++{- | Combinator for the @ondrop@ attribute.++ Example:++ > div ! ondrop "bar" $ "Hello."++ Result:++ > <div ondrop="bar">Hello.</div>+-}+ondrop ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ondrop = attr "ondrop"+{-# INLINE ondrop #-}++{- | Combinator for the @ondurationchange@ attribute.++ Example:++ > div ! ondurationchange "bar" $ "Hello."++ Result:++ > <div ondurationchange="bar">Hello.</div>+-}+ondurationchange ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ondurationchange = attr "ondurationchange"+{-# INLINE ondurationchange #-}++{- | Combinator for the @onemptied@ attribute.++ Example:++ > div ! onemptied "bar" $ "Hello."++ Result:++ > <div onemptied="bar">Hello.</div>+-}+onemptied ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onemptied = attr "onemptied"+{-# INLINE onemptied #-}++{- | Combinator for the @onended@ attribute.++ Example:++ > div ! onended "bar" $ "Hello."++ Result:++ > <div onended="bar">Hello.</div>+-}+onended ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onended = attr "onended"+{-# INLINE onended #-}++{- | Combinator for the @onerror@ attribute.++ Example:++ > div ! onerror "bar" $ "Hello."++ Result:++ > <div onerror="bar">Hello.</div>+-}+onerror ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onerror = attr "onerror"+{-# INLINE onerror #-}++{- | Combinator for the @onfocus@ attribute.++ Example:++ > div ! onfocus "bar" $ "Hello."++ Result:++ > <div onfocus="bar">Hello.</div>+-}+onfocus ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onfocus = attr "onfocus"+{-# INLINE onfocus #-}++{- | Combinator for the @onformchange@ attribute.++ Example:++ > div ! onformchange "bar" $ "Hello."++ Result:++ > <div onformchange="bar">Hello.</div>+-}+onformchange ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onformchange = attr "onformchange"+{-# INLINE onformchange #-}++{- | Combinator for the @onforminput@ attribute.++ Example:++ > div ! onforminput "bar" $ "Hello."++ Result:++ > <div onforminput="bar">Hello.</div>+-}+onforminput ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onforminput = attr "onforminput"+{-# INLINE onforminput #-}++{- | Combinator for the @onhaschange@ attribute.++ Example:++ > div ! onhaschange "bar" $ "Hello."++ Result:++ > <div onhaschange="bar">Hello.</div>+-}+onhaschange ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onhaschange = attr "onhaschange"+{-# INLINE onhaschange #-}++{- | Combinator for the @oninput@ attribute.++ Example:++ > div ! oninput "bar" $ "Hello."++ Result:++ > <div oninput="bar">Hello.</div>+-}+oninput ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+oninput = attr "oninput"+{-# INLINE oninput #-}++{- | Combinator for the @oninvalid@ attribute.++ Example:++ > div ! oninvalid "bar" $ "Hello."++ Result:++ > <div oninvalid="bar">Hello.</div>+-}+oninvalid ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+oninvalid = attr "oninvalid"+{-# INLINE oninvalid #-}++{- | Combinator for the @onkeydown@ attribute.++ Example:++ > div ! onkeydown "bar" $ "Hello."++ Result:++ > <div onkeydown="bar">Hello.</div>+-}+onkeydown ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onkeydown = attr "onkeydown"+{-# INLINE onkeydown #-}++{- | Combinator for the @onkeyup@ attribute.++ Example:++ > div ! onkeyup "bar" $ "Hello."++ Result:++ > <div onkeyup="bar">Hello.</div>+-}+onkeyup ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onkeyup = attr "onkeyup"+{-# INLINE onkeyup #-}++{- | Combinator for the @onload@ attribute.++ Example:++ > div ! onload "bar" $ "Hello."++ Result:++ > <div onload="bar">Hello.</div>+-}+onload ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onload = attr "onload"+{-# INLINE onload #-}++{- | Combinator for the @onloadeddata@ attribute.++ Example:++ > div ! onloadeddata "bar" $ "Hello."++ Result:++ > <div onloadeddata="bar">Hello.</div>+-}+onloadeddata ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onloadeddata = attr "onloadeddata"+{-# INLINE onloadeddata #-}++{- | Combinator for the @onloadedmetadata@ attribute.++ Example:++ > div ! onloadedmetadata "bar" $ "Hello."++ Result:++ > <div onloadedmetadata="bar">Hello.</div>+-}+onloadedmetadata ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onloadedmetadata = attr "onloadedmetadata"+{-# INLINE onloadedmetadata #-}++{- | Combinator for the @onloadstart@ attribute.++ Example:++ > div ! onloadstart "bar" $ "Hello."++ Result:++ > <div onloadstart="bar">Hello.</div>+-}+onloadstart ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onloadstart = attr "onloadstart"+{-# INLINE onloadstart #-}++{- | Combinator for the @onmessage@ attribute.++ Example:++ > div ! onmessage "bar" $ "Hello."++ Result:++ > <div onmessage="bar">Hello.</div>+-}+onmessage ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onmessage = attr "onmessage"+{-# INLINE onmessage #-}++{- | Combinator for the @onmousedown@ attribute.++ Example:++ > div ! onmousedown "bar" $ "Hello."++ Result:++ > <div onmousedown="bar">Hello.</div>+-}+onmousedown ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onmousedown = attr "onmousedown"+{-# INLINE onmousedown #-}++{- | Combinator for the @onmousemove@ attribute.++ Example:++ > div ! onmousemove "bar" $ "Hello."++ Result:++ > <div onmousemove="bar">Hello.</div>+-}+onmousemove ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onmousemove = attr "onmousemove"+{-# INLINE onmousemove #-}++{- | Combinator for the @onmouseout@ attribute.++ Example:++ > div ! onmouseout "bar" $ "Hello."++ Result:++ > <div onmouseout="bar">Hello.</div>+-}+onmouseout ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onmouseout = attr "onmouseout"+{-# INLINE onmouseout #-}++{- | Combinator for the @onmouseover@ attribute.++ Example:++ > div ! onmouseover "bar" $ "Hello."++ Result:++ > <div onmouseover="bar">Hello.</div>+-}+onmouseover ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onmouseover = attr "onmouseover"+{-# INLINE onmouseover #-}++{- | Combinator for the @onmouseup@ attribute.++ Example:++ > div ! onmouseup "bar" $ "Hello."++ Result:++ > <div onmouseup="bar">Hello.</div>+-}+onmouseup ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onmouseup = attr "onmouseup"+{-# INLINE onmouseup #-}++{- | Combinator for the @onmousewheel@ attribute.++ Example:++ > div ! onmousewheel "bar" $ "Hello."++ Result:++ > <div onmousewheel="bar">Hello.</div>+-}+onmousewheel ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onmousewheel = attr "onmousewheel"+{-# INLINE onmousewheel #-}++{- | Combinator for the @ononline@ attribute.++ Example:++ > div ! ononline "bar" $ "Hello."++ Result:++ > <div ononline="bar">Hello.</div>+-}+ononline ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ononline = attr "ononline"+{-# INLINE ononline #-}++{- | Combinator for the @onpagehide@ attribute.++ Example:++ > div ! onpagehide "bar" $ "Hello."++ Result:++ > <div onpagehide="bar">Hello.</div>+-}+onpagehide ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onpagehide = attr "onpagehide"+{-# INLINE onpagehide #-}++{- | Combinator for the @onpageshow@ attribute.++ Example:++ > div ! onpageshow "bar" $ "Hello."++ Result:++ > <div onpageshow="bar">Hello.</div>+-}+onpageshow ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onpageshow = attr "onpageshow"+{-# INLINE onpageshow #-}++{- | Combinator for the @onpause@ attribute.++ Example:++ > div ! onpause "bar" $ "Hello."++ Result:++ > <div onpause="bar">Hello.</div>+-}+onpause ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onpause = attr "onpause"+{-# INLINE onpause #-}++{- | Combinator for the @onplay@ attribute.++ Example:++ > div ! onplay "bar" $ "Hello."++ Result:++ > <div onplay="bar">Hello.</div>+-}+onplay ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onplay = attr "onplay"+{-# INLINE onplay #-}++{- | Combinator for the @onplaying@ attribute.++ Example:++ > div ! onplaying "bar" $ "Hello."++ Result:++ > <div onplaying="bar">Hello.</div>+-}+onplaying ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onplaying = attr "onplaying"+{-# INLINE onplaying #-}++{- | Combinator for the @onprogress@ attribute.++ Example:++ > div ! onprogress "bar" $ "Hello."++ Result:++ > <div onprogress="bar">Hello.</div>+-}+onprogress ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onprogress = attr "onprogress"+{-# INLINE onprogress #-}++{- | Combinator for the @onpropstate@ attribute.++ Example:++ > div ! onpropstate "bar" $ "Hello."++ Result:++ > <div onpropstate="bar">Hello.</div>+-}+onpropstate ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onpropstate = attr "onpropstate"+{-# INLINE onpropstate #-}++{- | Combinator for the @onratechange@ attribute.++ Example:++ > div ! onratechange "bar" $ "Hello."++ Result:++ > <div onratechange="bar">Hello.</div>+-}+onratechange ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onratechange = attr "onratechange"+{-# INLINE onratechange #-}++{- | Combinator for the @onreadystatechange@ attribute.++ Example:++ > div ! onreadystatechange "bar" $ "Hello."++ Result:++ > <div onreadystatechange="bar">Hello.</div>+-}+onreadystatechange ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onreadystatechange = attr "onreadystatechange"+{-# INLINE onreadystatechange #-}++{- | Combinator for the @onredo@ attribute.++ Example:++ > div ! onredo "bar" $ "Hello."++ Result:++ > <div onredo="bar">Hello.</div>+-}+onredo ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onredo = attr "onredo"+{-# INLINE onredo #-}++{- | Combinator for the @onresize@ attribute.++ Example:++ > div ! onresize "bar" $ "Hello."++ Result:++ > <div onresize="bar">Hello.</div>+-}+onresize ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onresize = attr "onresize"+{-# INLINE onresize #-}++{- | Combinator for the @onscroll@ attribute.++ Example:++ > div ! onscroll "bar" $ "Hello."++ Result:++ > <div onscroll="bar">Hello.</div>+-}+onscroll ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onscroll = attr "onscroll"+{-# INLINE onscroll #-}++{- | Combinator for the @onseeked@ attribute.++ Example:++ > div ! onseeked "bar" $ "Hello."++ Result:++ > <div onseeked="bar">Hello.</div>+-}+onseeked ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onseeked = attr "onseeked"+{-# INLINE onseeked #-}++{- | Combinator for the @onseeking@ attribute.++ Example:++ > div ! onseeking "bar" $ "Hello."++ Result:++ > <div onseeking="bar">Hello.</div>+-}+onseeking ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onseeking = attr "onseeking"+{-# INLINE onseeking #-}++{- | Combinator for the @onselect@ attribute.++ Example:++ > div ! onselect "bar" $ "Hello."++ Result:++ > <div onselect="bar">Hello.</div>+-}+onselect ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onselect = attr "onselect"+{-# INLINE onselect #-}++{- | Combinator for the @onstalled@ attribute.++ Example:++ > div ! onstalled "bar" $ "Hello."++ Result:++ > <div onstalled="bar">Hello.</div>+-}+onstalled ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onstalled = attr "onstalled"+{-# INLINE onstalled #-}++{- | Combinator for the @onstorage@ attribute.++ Example:++ > div ! onstorage "bar" $ "Hello."++ Result:++ > <div onstorage="bar">Hello.</div>+-}+onstorage ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onstorage = attr "onstorage"+{-# INLINE onstorage #-}++{- | Combinator for the @onsubmit@ attribute.++ Example:++ > div ! onsubmit "bar" $ "Hello."++ Result:++ > <div onsubmit="bar">Hello.</div>+-}+onsubmit ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onsubmit = attr "onsubmit"+{-# INLINE onsubmit #-}++{- | Combinator for the @onsuspend@ attribute.++ Example:++ > div ! onsuspend "bar" $ "Hello."++ Result:++ > <div onsuspend="bar">Hello.</div>+-}+onsuspend ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onsuspend = attr "onsuspend"+{-# INLINE onsuspend #-}++{- | Combinator for the @ontimeupdate@ attribute.++ Example:++ > div ! ontimeupdate "bar" $ "Hello."++ Result:++ > <div ontimeupdate="bar">Hello.</div>+-}+ontimeupdate ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ontimeupdate = attr "ontimeupdate"+{-# INLINE ontimeupdate #-}++{- | Combinator for the @onundo@ attribute.++ Example:++ > div ! onundo "bar" $ "Hello."++ Result:++ > <div onundo="bar">Hello.</div>+-}+onundo ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onundo = attr "onundo"+{-# INLINE onundo #-}++{- | Combinator for the @onunload@ attribute.++ Example:++ > div ! onunload "bar" $ "Hello."++ Result:++ > <div onunload="bar">Hello.</div>+-}+onunload ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onunload = attr "onunload"+{-# INLINE onunload #-}++{- | Combinator for the @onvolumechange@ attribute.++ Example:++ > div ! onvolumechange "bar" $ "Hello."++ Result:++ > <div onvolumechange="bar">Hello.</div>+-}+onvolumechange ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onvolumechange = attr "onvolumechange"+{-# INLINE onvolumechange #-}++{- | Combinator for the @onwaiting@ attribute.++ Example:++ > div ! onwaiting "bar" $ "Hello."++ Result:++ > <div onwaiting="bar">Hello.</div>+-}+onwaiting ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+onwaiting = attr "onwaiting"+{-# INLINE onwaiting #-}++{- | Combinator for the @open@ attribute.++ Example:++ > div ! open "bar" $ "Hello."++ Result:++ > <div open="bar">Hello.</div>+-}+open ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+open = attr "open"+{-# INLINE open #-}++{- | Combinator for the @optimum@ attribute.++ Example:++ > div ! optimum "bar" $ "Hello."++ Result:++ > <div optimum="bar">Hello.</div>+-}+optimum ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+optimum = attr "optimum"+{-# INLINE optimum #-}++{- | Combinator for the @pattern@ attribute.++ Example:++ > div ! pattern "bar" $ "Hello."++ Result:++ > <div pattern="bar">Hello.</div>+-}+pattern ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+pattern = attr "pattern"+{-# INLINE pattern #-}++{- | Combinator for the @ping@ attribute.++ Example:++ > div ! ping "bar" $ "Hello."++ Result:++ > <div ping="bar">Hello.</div>+-}+ping ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+ping = attr "ping"+{-# INLINE ping #-}++{- | Combinator for the @placeholder@ attribute.++ Example:++ > div ! placeholder "bar" $ "Hello."++ Result:++ > <div placeholder="bar">Hello.</div>+-}+placeholder ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+placeholder = attr "placeholder"+{-# INLINE placeholder #-}++{- | Combinator for the @preload@ attribute.++ Example:++ > div ! preload "bar" $ "Hello."++ Result:++ > <div preload="bar">Hello.</div>+-}+preload ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+preload = attr "preload"+{-# INLINE preload #-}++{- | Combinator for the @pubdate@ attribute.++ Example:++ > div ! pubdate "bar" $ "Hello."++ Result:++ > <div pubdate="bar">Hello.</div>+-}+pubdate ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+pubdate = attr "pubdate"+{-# INLINE pubdate #-}++{- | Combinator for the @radiogroup@ attribute.++ Example:++ > div ! radiogroup "bar" $ "Hello."++ Result:++ > <div radiogroup="bar">Hello.</div>+-}+radiogroup ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+radiogroup = attr "radiogroup"+{-# INLINE radiogroup #-}++{- | Combinator for the @readonly@ attribute.++ Example:++ > div ! readonly "bar" $ "Hello."++ Result:++ > <div readonly="bar">Hello.</div>+-}+readonly ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+readonly = attr "readonly"+{-# INLINE readonly #-}++{- | Combinator for the @rel@ attribute.++ Example:++ > div ! rel "bar" $ "Hello."++ Result:++ > <div rel="bar">Hello.</div>+-}+rel ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+rel = attr "rel"+{-# INLINE rel #-}++{- | Combinator for the @required@ attribute.++ Example:++ > div ! required "bar" $ "Hello."++ Result:++ > <div required="bar">Hello.</div>+-}+required ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+required = attr "required"+{-# INLINE required #-}++{- | Combinator for the @reversed@ attribute.++ Example:++ > div ! reversed "bar" $ "Hello."++ Result:++ > <div reversed="bar">Hello.</div>+-}+reversed ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+reversed = attr "reversed"+{-# INLINE reversed #-}++{- | Combinator for the @role@ attribute.++ Example:++ > div ! role "bar" $ "Hello."++ Result:++ > <div role="bar">Hello.</div>+-}+role ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+role = attr "role"+{-# INLINE role #-}++{- | Combinator for the @rows@ attribute.++ Example:++ > div ! rows "bar" $ "Hello."++ Result:++ > <div rows="bar">Hello.</div>+-}+rows ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+rows = attr "rows"+{-# INLINE rows #-}++{- | Combinator for the @rowspan@ attribute.++ Example:++ > div ! rowspan "bar" $ "Hello."++ Result:++ > <div rowspan="bar">Hello.</div>+-}+rowspan ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+rowspan = attr "rowspan"+{-# INLINE rowspan #-}++{- | Combinator for the @sandbox@ attribute.++ Example:++ > div ! sandbox "bar" $ "Hello."++ Result:++ > <div sandbox="bar">Hello.</div>+-}+sandbox ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+sandbox = attr "sandbox"+{-# INLINE sandbox #-}++{- | Combinator for the @scope@ attribute.++ Example:++ > div ! scope "bar" $ "Hello."++ Result:++ > <div scope="bar">Hello.</div>+-}+scope ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+scope = attr "scope"+{-# INLINE scope #-}++{- | Combinator for the @scoped@ attribute.++ Example:++ > div ! scoped "bar" $ "Hello."++ Result:++ > <div scoped="bar">Hello.</div>+-}+scoped ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+scoped = attr "scoped"+{-# INLINE scoped #-}++{- | Combinator for the @seamless@ attribute.++ Example:++ > div ! seamless "bar" $ "Hello."++ Result:++ > <div seamless="bar">Hello.</div>+-}+seamless ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+seamless = attr "seamless"+{-# INLINE seamless #-}++{- | Combinator for the @selected@ attribute.++ Example:++ > div ! selected "bar" $ "Hello."++ Result:++ > <div selected="bar">Hello.</div>+-}+selected ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+selected = attr "selected"+{-# INLINE selected #-}++{- | Combinator for the @shape@ attribute.++ Example:++ > div ! shape "bar" $ "Hello."++ Result:++ > <div shape="bar">Hello.</div>+-}+shape ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+shape = attr "shape"+{-# INLINE shape #-}++{- | Combinator for the @size@ attribute.++ Example:++ > div ! size "bar" $ "Hello."++ Result:++ > <div size="bar">Hello.</div>+-}+size ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+size = attr "size"+{-# INLINE size #-}++{- | Combinator for the @sizes@ attribute.++ Example:++ > div ! sizes "bar" $ "Hello."++ Result:++ > <div sizes="bar">Hello.</div>+-}+sizes ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+sizes = attr "sizes"+{-# INLINE sizes #-}++{- | Combinator for the @span@ attribute.++ Example:++ > div ! span "bar" $ "Hello."++ Result:++ > <div span="bar">Hello.</div>+-}+span ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+span = attr "span"+{-# INLINE span #-}++{- | Combinator for the @spellcheck@ attribute.++ Example:++ > div ! spellcheck "bar" $ "Hello."++ Result:++ > <div spellcheck="bar">Hello.</div>+-}+spellcheck ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+spellcheck = attr "spellcheck"+{-# INLINE spellcheck #-}++{- | Combinator for the @src@ attribute.++ Example:++ > div ! src "bar" $ "Hello."++ Result:++ > <div src="bar">Hello.</div>+-}+src ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+src = attr "src"+{-# INLINE src #-}++{- | Combinator for the @srcdoc@ attribute.++ Example:++ > div ! srcdoc "bar" $ "Hello."++ Result:++ > <div srcdoc="bar">Hello.</div>+-}+srcdoc ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+srcdoc = attr "srcdoc"+{-# INLINE srcdoc #-}++{- | Combinator for the @start@ attribute.++ Example:++ > div ! start "bar" $ "Hello."++ Result:++ > <div start="bar">Hello.</div>+-}+start ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+start = attr "start"+{-# INLINE start #-}++{- | Combinator for the @step@ attribute.++ Example:++ > div ! step "bar" $ "Hello."++ Result:++ > <div step="bar">Hello.</div>+-}+step ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+step = attr "step"+{-# INLINE step #-}++{- | Combinator for the @style@ attribute.++ Example:++ > div ! style "bar" $ "Hello."++ Result:++ > <div style="bar">Hello.</div>+-}+style ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+style = attr "style"+{-# INLINE style #-}++{- | Combinator for the @subject@ attribute.++ Example:++ > div ! subject "bar" $ "Hello."++ Result:++ > <div subject="bar">Hello.</div>+-}+subject ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+subject = attr "subject"+{-# INLINE subject #-}++{- | Combinator for the @summary@ attribute.++ Example:++ > div ! summary "bar" $ "Hello."++ Result:++ > <div summary="bar">Hello.</div>+-}+summary ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+summary = attr "summary"+{-# INLINE summary #-}++{- | Combinator for the @tabindex@ attribute.++ Example:++ > div ! tabindex "bar" $ "Hello."++ Result:++ > <div tabindex="bar">Hello.</div>+-}+tabindex ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+tabindex = attr "tabindex"+{-# INLINE tabindex #-}++{- | Combinator for the @target@ attribute.++ Example:++ > div ! target "bar" $ "Hello."++ Result:++ > <div target="bar">Hello.</div>+-}+target ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+target = attr "target"+{-# INLINE target #-}++{- | Combinator for the @title@ attribute.++ Example:++ > div ! title "bar" $ "Hello."++ Result:++ > <div title="bar">Hello.</div>+-}+title ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+title = attr "title"+{-# INLINE title #-}++{- | Combinator for the @type@ attribute.++ Example:++ > div ! type_ "bar" $ "Hello."++ Result:++ > <div type="bar">Hello.</div>+-}+type_ ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+type_ = attr "type"+{-# INLINE type_ #-}++{- | Combinator for the @usemap@ attribute.++ Example:++ > div ! usemap "bar" $ "Hello."++ Result:++ > <div usemap="bar">Hello.</div>+-}+usemap ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+usemap = attr "usemap"+{-# INLINE usemap #-}++{- | Combinator for the @value@ attribute.++ Example:++ > div ! value "bar" $ "Hello."++ Result:++ > <div value="bar">Hello.</div>+-}+value ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+value = attr "value"+{-# INLINE value #-}++{- | Combinator for the @width@ attribute.++ Example:++ > div ! width "bar" $ "Hello."++ Result:++ > <div width="bar">Hello.</div>+-}+width ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+width = attr "width"+{-# INLINE width #-}++{- | Combinator for the @wrap@ attribute.++ Example:++ > div ! wrap "bar" $ "Hello."++ Result:++ > <div wrap="bar">Hello.</div>+-}+wrap ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+wrap = attr "wrap"+{-# INLINE wrap #-}++{- | Combinator for the @xmlns@ attribute.++ Example:++ > div ! xmlns "bar" $ "Hello."++ Result:++ > <div xmlns="bar">Hello.</div>+-}+xmlns ::+    ToLogStr s =>+    -- | Attribute value.+    s ->+    -- | Resulting attribute.+    Attr+xmlns = attr "xmlns"+{-# INLINE xmlns #-}
+ src/Data/Fmt/Code.hs view
@@ -0,0 +1,324 @@+module Data.Fmt.Code (+    v,++    -- * Character encodings+    c,+    c7,+    c8,+    s,+    s7,+    s8,++    -- * Ascii float encodings+    e,+    f,+    g,++    -- * Decimal encodings+    d,+    hhd,+    hd,+    ld,+    lld,+    u,+    hhu,+    hu,+    lu,+    llu,++    -- * Hexadecimal encodings+    x,+    hhx,+    hx,+    hx',+    lx,+    lx',+    llx,+    llx',++    -- * Binary encodings+    b,+    b',+    hhb,+    hb,+    hb',+    lb,+    lb',+    llb,+    llb',+) where++import Data.ByteString (ByteString)+import qualified Data.ByteString.Builder as BL+import qualified Data.ByteString.Lazy.Char8 as BL+import Data.Fmt+import Data.Int+import Data.Word+import qualified Numeric as N++{- $setup+ >>> import Text.Printf+ >>> :load Data.Fmt+-}++{- | Encode a loggable value.++ Semantics are similar to 'ByteString.Printf.printf':++ >>> Text.Printf.printf "%v" 42 :: String+ "42"+ >>> runLogFmt v 42+ "42"+-}+{-# INLINE v #-}+v :: ToLogStr a => Fmt1 LogStr s a+v = fmt1 toLogStr++-- Character encodings++-------------------------++-- | Format a character.+{-# INLINE c #-}+c :: IsString m => Fmt1 m s Char+c = fmt1 (fromString . pure)++-- | ASCII encode a 'Char'.+{-# INLINE c7 #-}+c7 :: Fmt1 LogStr s Char+c7 = fmt1 $ toLogStr . BL.char7++-- | Latin-1 (ISO/IEC 8859-1) encode a 'Char'.+{-# INLINE c8 #-}+c8 :: Fmt1 LogStr s Char+c8 = fmt1 $ toLogStr . BL.char8++-- | Format a showable value.+{-# INLINE s #-}+s :: (IsString m, Show a) => Fmt1 m s a+s = fmt1 (fromString . show)++-- | ASCII encode a 'String'.+{-# INLINE s7 #-}+s7 :: Fmt1 LogStr s String+s7 = fmt1 $ toLogStr . BL.string7++-- | Latin-1 (ISO/IEC 8859-1) encode a 'String'.+{-# INLINE s8 #-}+s8 :: Fmt1 LogStr s String+s8 = fmt1 $ toLogStr . BL.string8++-- Floating point++-------------------------++{- | Format a floating point number to a given number of digits of precision.++ Semantics are similar to 'ByteString.Printf.printf':++ >>> Text.Printf.printf "%.5e" pi :: String+ "3.14159e0"+ >>> runLogFmt (e 5) pi+ "3.14159e0"+-}+e :: (IsString m, RealFloat a) => Int -> Fmt1 m s a+e prec = fmt1 $ fromString . flip (N.showEFloat $ Just prec) []++{- | Format a floating point number to a given number of digits of precision.++ Semantics are similar to 'ByteString.Printf.printf':++ >>> Text.Printf.printf "%.5f" maximal32 :: String+ "340282330000000000000000000000000000000.00000"+ >>> runLogFmt (f 5) maximal32+ "340282330000000000000000000000000000000.00000"+-}+f :: (IsString m, RealFloat a) => Int -> Fmt1 m s a+f prec = fmt1 $ fromString . flip (N.showFFloat $ Just prec) []++{- | Format a floating point number to a given number of digits of precision.++ Semantics are similar to 'ByteString.Printf.printf':++ >>> Text.Printf.printf "%.5g" maximal32 :: String+ "3.40282e38"+ >>> runLogFmt (g 5) maximal32+ "3.40282e38"+-}+g :: (IsString m, RealFloat a) => Int -> Fmt1 m s a+g prec = fmt1 $ fromString . flip (N.showGFloat $ Just prec) []++-- Decimal encodings++-------------------------++-- | Decimal encoding of an 'Int' using the ASCII digits.+{-# INLINE d #-}+d :: Fmt1 LogStr s Int+d = fmt1 $ toLogStr . BL.intDec++{- | Decimal encoding of an 'Int8' using the ASCII digits.++ e.g.++ > toLazyByteString (int8Dec 42)   = "42"+ > toLazyByteString (int8Dec (-1)) = "-1"+-}+{-# INLINE hhd #-}+hhd :: Fmt1 LogStr s Int8+hhd = fmt1 $ toLogStr . BL.int8Dec++-- | Decimal encoding of an 'Int16' using the ASCII digits.+{-# INLINE hd #-}+hd :: Fmt1 LogStr s Int16+hd = fmt1 $ toLogStr . BL.int16Dec++-- | Decimal encoding of an 'Int32' using the ASCII digits.+{-# INLINE ld #-}+ld :: Fmt1 LogStr s Int32+ld = fmt1 $ toLogStr . BL.int32Dec++-- | Decimal encoding of an 'Int64' using the ASCII digits.+{-# INLINE lld #-}+lld :: Fmt1 LogStr s Int64+lld = fmt1 $ toLogStr . BL.int64Dec++-- | Decimal encoding of a 'Word' using the ASCII digits.+{-# INLINE u #-}+u :: Fmt1 LogStr s Word+u = fmt1 $ toLogStr . BL.wordDec++-- | Decimal encoding of a 'Word8' using the ASCII digits.+{-# INLINE hhu #-}+hhu :: Fmt1 LogStr s Word8+hhu = fmt1 $ toLogStr . BL.word8Dec++-- | Decimal encoding of a 'Word16' using the ASCII digits.+{-# INLINE hu #-}+hu :: Fmt1 LogStr s Word16+hu = fmt1 $ toLogStr . BL.word16Dec++-- | Decimal encoding of a 'Word32' using the ASCII digits.+{-# INLINE lu #-}+lu :: Fmt1 LogStr s Word32+lu = fmt1 $ toLogStr . BL.word32Dec++-- | Decimal encoding of a 'Word64' using the ASCII digits.+{-# INLINE llu #-}+llu :: Fmt1 LogStr s Word64+llu = fmt1 $ toLogStr . BL.word64Dec++-- Hexadecimal encodings+--------------------++-- | Shortest hexadecimal encoding of a 'Word' using lower-case characters.+{-# INLINE x #-}+x :: Fmt1 LogStr s Word+x = fmt1 $ toLogStr . BL.wordHex++-- | Shortest hexadecimal encoding of a 'Word8' using lower-case characters.+{-# INLINE hhx #-}+hhx :: Fmt1 LogStr s Word8+hhx = fmt1 $ toLogStr . BL.word8Hex++-- | Encode a 'Word8' using 2 nibbles (hexadecimal digits).+{-# INLINE hhx' #-}+hhx' :: Fmt1 LogStr s Word8+hhx' = fmt1 $ toLogStr . BL.word8HexFixed++-- | Shortest hexadecimal encoding of a 'Word16' using lower-case characters.+{-# INLINE hx #-}+hx :: Fmt1 LogStr s Word16+hx = fmt1 $ toLogStr . BL.word16Hex++-- | Encode a 'Word16' using 4 nibbles.+{-# INLINE hx' #-}+hx' :: Fmt1 LogStr s Word16+hx' = fmt1 $ toLogStr . BL.word16HexFixed++-- | Shortest hexadecimal encoding of a 'Word32' using lower-case characters.+{-# INLINE lx #-}+lx :: Fmt1 LogStr s Word32+lx = fmt1 $ toLogStr . BL.word32Hex++-- | Encode a 'Word32' using 8 nibbles.+{-# INLINE lx' #-}+lx' :: Fmt1 LogStr s Word32+lx' = fmt1 $ toLogStr . BL.word32HexFixed++{- | Shortest hexadecimal encoding of a 'Word64' using lower-case characters.++ Semantics are similar to 'Text.Printf.printf':++ >>> Text.printf "%s: %llx" "Val" (-7) :: String+ "Val: fffffffffffffff9"+ >>> printf (s % ": " % llx) "Val" (-7)+ "Val: fffffffffffffff9"+-}+{-# INLINE llx #-}+llx :: Fmt1 LogStr s Word64+llx = fmt1 $ toLogStr . BL.word64Hex++-- | Encode a 'Word64' using 16 nibbles.+{-# INLINE llx' #-}+llx' :: Fmt1 LogStr s Word64+llx' = fmt1 $ toLogStr . BL.word64HexFixed++-- Binary encodings+--------------------++-- | Format a lazy byte string.+b :: Fmt1 LogStr s BL.ByteString+b = fmt1 toLogStr+{-# INLINE b #-}++{- | Format a strict byte string.++ @ 'fmap' (. 'Data.ByteString.pack') 't'' :: 'Fmt1' 'Data.ByteString.Builder.Builder' s 'String' @+-}+b' :: Fmt1 LogStr s ByteString+b' = fmt1 toLogStr+{-# INLINE b' #-}++-- | Encode a 'Word8' as-is+{-# INLINE hhb #-}+hhb :: Fmt1 LogStr s Word8+hhb = fmt1 $ toLogStr . BL.word8++-- | Encode a 'Word16' using little-endian format.+{-# INLINE hb #-}+hb :: Fmt1 LogStr s Word16+hb = fmt1 $ toLogStr . BL.word16LE++-- | Encode a 'Word16' using big-endian format.+{-# INLINE hb' #-}+hb' :: Fmt1 LogStr s Word16+hb' = fmt1 $ toLogStr . BL.word16BE++-- | Encode a 'Word32' using little-endian format.+{-# INLINE lb #-}+lb :: Fmt1 LogStr s Word32+lb = fmt1 $ toLogStr . BL.word32LE++-- | Encode a 'Word32' using big-endian format.+{-# INLINE lb' #-}+lb' :: Fmt1 LogStr s Word32+lb' = fmt1 $ toLogStr . BL.word32BE++{- | Encode a 'Word64' using little-endian format.++ Semantics are similar to 'Tebt.Printf.printf':++ >>> Text.printf "%s: %llb" "Val" (-7) :: String+ "Val: fffffffffffffff9"+ >>> printf (s % ": " % llb) "Val" (-7)+ "Val: fffffffffffffff9"+-}+{-# INLINE llb #-}+llb :: Fmt1 LogStr s Word64+llb = fmt1 $ toLogStr . BL.word64LE++-- | Encode a 'Word64' using big-endian format.+{-# INLINE llb' #-}+llb' :: Fmt1 LogStr s Word64+llb' = fmt1 $ toLogStr . BL.word64BE
+ src/Data/Fmt/Html.hs view
@@ -0,0 +1,2120 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications #-}++{- | Html5 formatting.++ The API is similar to < https://hackage.haskell.org/package/blaze-html >.+-}+module Data.Fmt.Html (+    -- * Html+    Html,+    Attr,+    toHtml,+    comment,+    Element (..),+    (!?),+   +    numbers,+    -- * Elements+    docType,+    docTypeHtml,+    a,+    abbr,+    address,+    area,+    article,+    aside,+    audio,+    b,+    base,+    bdo,+    blockquote,+    body,+    br,+    button,+    canvas,+    caption,+    cite,+    code,+    col,+    colgroup,+    command,+    datalist,+    dd,+    del,+    details,+    dfn,+    div,+    dl,+    dt,+    em,+    embed,+    fieldset,+    figcaption,+    figure,+    footer,+    form,+    h1,+    h2,+    h3,+    h4,+    h5,+    h6,+    head,+    header,+    hgroup,+    hr,+    html,+    i,+    iframe,+    img,+    input,+    ins,+    kbd,+    keygen,+    label,+    legend,+    li,+    link,+    main,+    map,+    mark,+    menu,+    menuitem,+    meta,+    meter,+    nav,+    noscript,+    object,+    ol,+    optgroup,+    option,+    output,+    p,+    param,+    pre,+    progress,+    q,+    rp,+    rt,+    ruby,+    samp,+    script,+    section,+    select,+    small,+    source,+    span,+    strong,+    style,+    sub,+    summary,+    sup,+    table,+    tbody,+    td,+    textarea,+    tfoot,+    th,+    thead,+    time,+    title,+    tr,+    track,+    u,+    ul,+    var,+    video,+    wbr,+    contact+) where++import Data.Fmt+import Prelude hiding (div, head, map, span)++import Data.Fmt.Attr (href)+++contact :: Html LogStr+contact = p "You can reach me at" % ul . spr . li $ do+    c1 <- a ! href @String "https://example.com" $ "Website"+    c2 <- a ! href @String "mailto:cmk@example.com" $ "Email"+    pure $ c1 <> c2++-- "<p>You can reach me at</p><ul><li><a href=\"https://example.com\">Website</a></li><li><a href=\"mailto:cmk@example.com\">Email</a></li></ul>"++-- | Run a monadic expression.+--+-- This executes the formatting commands contained in the expression and +-- returns the result as a variable.+run :: Fmt m m n -> Fmt n a a+run = fmt . runFmt++-- > runLogFmt $ numbers 2+-- "<html><p>A list of numbers:</p><html><ul><li>1</li><li>2</li></ul></html><p>The end.</p></html>"+numbers :: Int -> Html LogStr+numbers n = html $ do+    l <- ul . cat $ li . toHtml <$> [1 .. n]+    cat+        [ p "A list of numbers:"+        , fmt l+        , p "The end."+        ]++-- | Create a < https://en.wikipedia.org/wiki/HTML_element#Syntax tag > for an element.+element :: String -> Html a -> Html a+element = enclose <$> (enclose "<" ">" . toHtml) <*> (enclose "</" ">" . toHtml)++element_ :: String -> Html a+element_ = enclose "<" " />" . toHtml++-- Elements++-------------------------++{- | Combinator for the document type. This should be placed at the top+ of every HTML page.++ Example:++ > docType++ Result:++ > <!DOCTYPE HTML>+-}+docType ::+    -- | The document type HTML.+    Html a+docType = "<!DOCTYPE HTML>\n"+{-# INLINE docType #-}++{- | Combinator for the @\<html>@ element. This combinator will also+ insert the correct doctype.++ Example:++ > docTypeHtml $ span $ fmt "foo"++ Result:++ > <!DOCTYPE HTML>+ > <html><span>foo</span></html>+-}+docTypeHtml ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+docTypeHtml inner = docType % html inner+{-# INLINE docTypeHtml #-}++{- | Combinator for the @\<a>@ element.++ Example:++ > a $ span $ fmt "foo"++ Result:++ > <a><span>foo</span></a>+-}+a ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+a = element "a"+{-# INLINE a #-}++{- | Combinator for the @\<abbr>@ element.++ Example:++ > abbr $ span $ fmt "foo"++ Result:++ > <abbr><span>foo</span></abbr>+-}+abbr ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+abbr = element "abbr"+{-# INLINE abbr #-}++{- | Combinator for the @\<address>@ element.++ Example:++ > address $ span $ fmt "foo"++ Result:++ > <address><span>foo</span></address>+-}+address ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+address = element "address"+{-# INLINE address #-}++{- | Combinator for the @\<area />@ element.++ Example:++ > area++ Result:++ > <area />+-}+area ::+    -- | Resulting HTML.+    Html a+area = element_ "area"+{-# INLINE area #-}++{- | Combinator for the @\<article>@ element.++ Example:++ > article $ span $ fmt "foo"++ Result:++ > <article><span>foo</span></article>+-}+article ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+article = element "article"+{-# INLINE article #-}++{- | Combinator for the @\<aside>@ element.++ Example:++ > aside $ span $ fmt "foo"++ Result:++ > <aside><span>foo</span></aside>+-}+aside ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+aside = element "aside"+{-# INLINE aside #-}++{- | Combinator for the @\<audio>@ element.++ Example:++ > audio $ span $ fmt "foo"++ Result:++ > <audio><span>foo</span></audio>+-}+audio ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+audio = element "audio"+{-# INLINE audio #-}++{- | Combinator for the @\<b>@ element.++ Example:++ > b $ span $ fmt "foo"++ Result:++ > <b><span>foo</span></b>+-}+b ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+b = element "b"+{-# INLINE b #-}++{- | Combinator for the @\<base />@ element.++ Example:++ > base++ Result:++ > <base />+-}+base ::+    -- | Resulting HTML.+    Html a+base = element_ "base"+{-# INLINE base #-}++{- | Combinator for the @\<bdo>@ element.++ Example:++ > bdo $ span $ fmt "foo"++ Result:++ > <bdo><span>foo</span></bdo>+-}+bdo ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+bdo = element "bdo"+{-# INLINE bdo #-}++{- | Combinator for the @\<blockquote>@ element.++ Example:++ > blockquote $ span $ fmt "foo"++ Result:++ > <blockquote><span>foo</span></blockquote>+-}+blockquote ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+blockquote = element "blockquote"+{-# INLINE blockquote #-}++{- | Combinator for the @\<body>@ element.++ Example:++ > body $ span $ fmt "foo"++ Result:++ > <body><span>foo</span></body>+-}+body ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+body = element "body"+{-# INLINE body #-}++{- | Combinator for the @\<br />@ element.++ Example:++ > br++ Result:++ > <br />+-}+br ::+    -- | Resulting HTML.+    Html a+br = element_ "br"+{-# INLINE br #-}++{- | Combinator for the @\<button>@ element.++ Example:++ > button $ span $ fmt "foo"++ Result:++ > <button><span>foo</span></button>+-}+button ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+button = element "button"+{-# INLINE button #-}++{- | Combinator for the @\<canvas>@ element.++ Example:++ > canvas $ span $ fmt "foo"++ Result:++ > <canvas><span>foo</span></canvas>+-}+canvas ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+canvas = element "canvas"+{-# INLINE canvas #-}++{- | Combinator for the @\<caption>@ element.++ Example:++ > caption $ span $ fmt "foo"++ Result:++ > <caption><span>foo</span></caption>+-}+caption ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+caption = element "caption"+{-# INLINE caption #-}++{- | Combinator for the @\<cite>@ element.++ Example:++ > cite $ span $ fmt "foo"++ Result:++ > <cite><span>foo</span></cite>+-}+cite ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+cite = element "cite"+{-# INLINE cite #-}++{- | Combinator for the @\<code>@ element.++ Example:++ > code $ span $ fmt "foo"++ Result:++ > <code><span>foo</span></code>+-}+code ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+code = element "code"+{-# INLINE code #-}++{- | Combinator for the @\<col />@ element.++ Example:++ > col++ Result:++ > <col />+-}+col ::+    -- | Resulting HTML.+    Html a+col = element_ "col"+{-# INLINE col #-}++{- | Combinator for the @\<colgroup>@ element.++ Example:++ > colgroup $ span $ fmt "foo"++ Result:++ > <colgroup><span>foo</span></colgroup>+-}+colgroup ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+colgroup = element "colgroup"+{-# INLINE colgroup #-}++{- | Combinator for the @\<command>@ element.++ Example:++ > command $ span $ fmt "foo"++ Result:++ > <command><span>foo</span></command>+-}+command ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+command = element "command"+{-# INLINE command #-}++{- | Combinator for the @\<datalist>@ element.++ Example:++ > datalist $ span $ fmt "foo"++ Result:++ > <datalist><span>foo</span></datalist>+-}+datalist ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+datalist = element "datalist"+{-# INLINE datalist #-}++{- | Combinator for the @\<dd>@ element.++ Example:++ > dd $ span $ fmt "foo"++ Result:++ > <dd><span>foo</span></dd>+-}+dd ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+dd = element "dd"+{-# INLINE dd #-}++{- | Combinator for the @\<del>@ element.++ Example:++ > del $ span $ fmt "foo"++ Result:++ > <del><span>foo</span></del>+-}+del ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+del = element "del"+{-# INLINE del #-}++{- | Combinator for the @\<details>@ element.++ Example:++ > details $ span $ fmt "foo"++ Result:++ > <details><span>foo</span></details>+-}+details ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+details = element "details"+{-# INLINE details #-}++{- | Combinator for the @\<dfn>@ element.++ Example:++ > dfn $ span $ fmt "foo"++ Result:++ > <dfn><span>foo</span></dfn>+-}+dfn ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+dfn = element "dfn"+{-# INLINE dfn #-}++{- | Combinator for the @\<div>@ element.++ Example:++ > div $ span $ fmt "foo"++ Result:++ > <div><span>foo</span></div>+-}+div ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+div = element "div"+{-# INLINE div #-}++{- | Combinator for the @\<dl>@ element.++ Example:++ > dl $ span $ fmt "foo"++ Result:++ > <dl><span>foo</span></dl>+-}+dl ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+dl = element "dl"+{-# INLINE dl #-}++{- | Combinator for the @\<dt>@ element.++ Example:++ > dt $ span $ fmt "foo"++ Result:++ > <dt><span>foo</span></dt>+-}+dt ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+dt = element "dt"+{-# INLINE dt #-}++{- | Combinator for the @\<em>@ element.++ Example:++ > em $ span $ fmt "foo"++ Result:++ > <em><span>foo</span></em>+-}+em ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+em = element "em"+{-# INLINE em #-}++{- | Combinator for the @\<embed />@ element.++ Example:++ > embed++ Result:++ > <embed />+-}+embed ::+    -- | Resulting HTML.+    Html a+embed = element_ "embed"+{-# INLINE embed #-}++{- | Combinator for the @\<fieldset>@ element.++ Example:++ > fieldset $ span $ fmt "foo"++ Result:++ > <fieldset><span>foo</span></fieldset>+-}+fieldset ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+fieldset = element "fieldset"+{-# INLINE fieldset #-}++{- | Combinator for the @\<figcaption>@ element.++ Example:++ > figcaption $ span $ fmt "foo"++ Result:++ > <figcaption><span>foo</span></figcaption>+-}+figcaption ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+figcaption = element "figcaption"+{-# INLINE figcaption #-}++{- | Combinator for the @\<figure>@ element.++ Example:++ > figure $ span $ fmt "foo"++ Result:++ > <figure><span>foo</span></figure>+-}+figure ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+figure = element "figure"+{-# INLINE figure #-}++{- | Combinator for the @\<footer>@ element.++ Example:++ > footer $ span $ fmt "foo"++ Result:++ > <footer><span>foo</span></footer>+-}+footer ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+footer = element "footer"+{-# INLINE footer #-}++{- | Combinator for the @\<form>@ element.++ Example:++ > form $ span $ fmt "foo"++ Result:++ > <form><span>foo</span></form>+-}+form ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+form = element "form"+{-# INLINE form #-}++{- | Combinator for the @\<h1>@ element.++ Example:++ > h1 $ span $ fmt "foo"++ Result:++ > <h1><span>foo</span></h1>+-}+h1 ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+h1 = element "h1"+{-# INLINE h1 #-}++{- | Combinator for the @\<h2>@ element.++ Example:++ > h2 $ span $ fmt "foo"++ Result:++ > <h2><span>foo</span></h2>+-}+h2 ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+h2 = element "h2"+{-# INLINE h2 #-}++{- | Combinator for the @\<h3>@ element.++ Example:++ > h3 $ span $ fmt "foo"++ Result:++ > <h3><span>foo</span></h3>+-}+h3 ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+h3 = element "h3"+{-# INLINE h3 #-}++{- | Combinator for the @\<h4>@ element.++ Example:++ > h4 $ span $ fmt "foo"++ Result:++ > <h4><span>foo</span></h4>+-}+h4 ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+h4 = element "h4"+{-# INLINE h4 #-}++{- | Combinator for the @\<h5>@ element.++ Example:++ > h5 $ span $ fmt "foo"++ Result:++ > <h5><span>foo</span></h5>+-}+h5 ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+h5 = element "h5"+{-# INLINE h5 #-}++{- | Combinator for the @\<h6>@ element.++ Example:++ > h6 $ span $ fmt "foo"++ Result:++ > <h6><span>foo</span></h6>+-}+h6 ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+h6 = element "h6"+{-# INLINE h6 #-}++{- | Combinator for the @\<head>@ element.++ Example:++ > head $ span $ fmt "foo"++ Result:++ > <head><span>foo</span></head>+-}+head ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+head = element "head"+{-# INLINE head #-}++{- | Combinator for the @\<header>@ element.++ Example:++ > header $ span $ fmt "foo"++ Result:++ > <header><span>foo</span></header>+-}+header ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+header = element "header"+{-# INLINE header #-}++{- | Combinator for the @\<hgroup>@ element.++ Example:++ > hgroup $ span $ fmt "foo"++ Result:++ > <hgroup><span>foo</span></hgroup>+-}+hgroup ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+hgroup = element "hgroup"+{-# INLINE hgroup #-}++{- | Combinator for the @\<hr />@ element.++ Example:++ > hr++ Result:++ > <hr />+-}+hr ::+    -- | Resulting HTML.+    Html a+hr = element_ "hr"+{-# INLINE hr #-}++{- | Combinator for the @\<html>@ element.++ Example:++ > html $ span $ fmt "foo"++ Result:++ > <html><span>foo</span></html>+-}+html ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+html = element "html"+{-# INLINE html #-}++{- | Combinator for the @\<i>@ element.++ Example:++ > i $ span $ fmt "foo"++ Result:++ > <i><span>foo</span></i>+-}+i ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+i = element "i"+{-# INLINE i #-}++{- | Combinator for the @\<iframe>@ element.++ Example:++ > iframe $ span $ fmt "foo"++ Result:++ > <iframe><span>foo</span></iframe>+-}+iframe ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+iframe = element "iframe"+{-# INLINE iframe #-}++{- | Combinator for the @\<img />@ element.++ Example:++ > img++ Result:++ > <img />+-}+img ::+    -- | Resulting HTML.+    Html a+img = element_ "img"+{-# INLINE img #-}++{- | Combinator for the @\<input />@ element.++ Example:++ > input++ Result:++ > <input />+-}+input ::+    -- | Resulting HTML.+    Html a+input = element_ "input"+{-# INLINE input #-}++{- | Combinator for the @\<ins>@ element.++ Example:++ > ins $ span $ fmt "foo"++ Result:++ > <ins><span>foo</span></ins>+-}+ins ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+ins = element "ins"+{-# INLINE ins #-}++{- | Combinator for the @\<kbd>@ element.++ Example:++ > kbd $ span $ fmt "foo"++ Result:++ > <kbd><span>foo</span></kbd>+-}+kbd ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+kbd = element "kbd"+{-# INLINE kbd #-}++{- | Combinator for the @\<keygen />@ element.++ Example:++ > keygen++ Result:++ > <keygen />+-}+keygen ::+    -- | Resulting HTML.+    Html a+keygen = element_ "keygen"+{-# INLINE keygen #-}++{- | Combinator for the @\<label>@ element.++ Example:++ > label $ span $ fmt "foo"++ Result:++ > <label><span>foo</span></label>+-}+label ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+label = element "label"+{-# INLINE label #-}++{- | Combinator for the @\<legend>@ element.++ Example:++ > legend $ span $ fmt "foo"++ Result:++ > <legend><span>foo</span></legend>+-}+legend ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+legend = element "legend"+{-# INLINE legend #-}++{- | Combinator for the @\<li>@ element.++ Example:++ > li $ span $ fmt "foo"++ Result:++ > <li><span>foo</span></li>+-}+li ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+li = element "li"+{-# INLINE li #-}++{- | Combinator for the @\<link />@ element.++ Example:++ > link++ Result:++ > <link />+-}+link ::+    -- | Resulting HTML.+    Html a+link = element_ "link"+{-# INLINE link #-}++{- | Combinator for the @\<main>@ element.++ Example:++ > main $ span $ fmt "foo"++ Result:++ > <main><span>foo</span></main>+-}+main ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+main = element "main"+{-# INLINE main #-}++{- | Combinator for the @\<map>@ element.++ Example:++ > map $ span $ fmt "foo"++ Result:++ > <map><span>foo</span></map>+-}+map ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+map = element "map"+{-# INLINE map #-}++{- | Combinator for the @\<mark>@ element.++ Example:++ > mark $ span $ fmt "foo"++ Result:++ > <mark><span>foo</span></mark>+-}+mark ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+mark = element "mark"+{-# INLINE mark #-}++{- | Combinator for the @\<menu>@ element.++ Example:++ > menu $ span $ fmt "foo"++ Result:++ > <menu><span>foo</span></menu>+-}+menu ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+menu = element "menu"+{-# INLINE menu #-}++{- | Combinator for the @\<menuitem />@ element.++ Example:++ > menuitem++ Result:++ > <menuitem />+-}+menuitem ::+    -- | Resulting HTML.+    Html a+menuitem = element_ "menuitem"+{-# INLINE menuitem #-}++{- | Combinator for the @\<meta />@ element.++ Example:++ > meta++ Result:++ > <meta />+-}+meta ::+    -- | Resulting HTML.+    Html a+meta = element_ "meta"+{-# INLINE meta #-}++{- | Combinator for the @\<meter>@ element.++ Example:++ > meter $ span $ fmt "foo"++ Result:++ > <meter><span>foo</span></meter>+-}+meter ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+meter = element "meter"+{-# INLINE meter #-}++{- | Combinator for the @\<nav>@ element.++ Example:++ > nav $ span $ fmt "foo"++ Result:++ > <nav><span>foo</span></nav>+-}+nav ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+nav = element "nav"+{-# INLINE nav #-}++{- | Combinator for the @\<noscript>@ element.++ Example:++ > noscript $ span $ fmt "foo"++ Result:++ > <noscript><span>foo</span></noscript>+-}+noscript ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+noscript = element "noscript"+{-# INLINE noscript #-}++{- | Combinator for the @\<object>@ element.++ Example:++ > object $ span $ fmt "foo"++ Result:++ > <object><span>foo</span></object>+-}+object ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+object = element "object"+{-# INLINE object #-}++{- | Combinator for the @\<ol>@ element.++ Example:++ > ol $ span $ fmt "foo"++ Result:++ > <ol><span>foo</span></ol>+-}+ol ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+ol = element "ol"+{-# INLINE ol #-}++{- | Combinator for the @\<optgroup>@ element.++ Example:++ > optgroup $ span $ fmt "foo"++ Result:++ > <optgroup><span>foo</span></optgroup>+-}+optgroup ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+optgroup = element "optgroup"+{-# INLINE optgroup #-}++{- | Combinator for the @\<option>@ element.++ Example:++ > option $ span $ fmt "foo"++ Result:++ > <option><span>foo</span></option>+-}+option ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+option = element "option"+{-# INLINE option #-}++{- | Combinator for the @\<output>@ element.++ Example:++ > output $ span $ fmt "foo"++ Result:++ > <output><span>foo</span></output>+-}+output ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+output = element "output"+{-# INLINE output #-}++{- | Combinator for the @\<p>@ element.++ Example:++ > p $ span $ fmt "foo"++ Result:++ > <p><span>foo</span></p>+-}+p ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+p = element "p"+{-# INLINE p #-}++{- | Combinator for the @\<param />@ element.++ Example:++ > param++ Result:++ > <param />+-}+param ::+    -- | Resulting HTML.+    Html a+param = element_ "param"+{-# INLINE param #-}++{- | Combinator for the @\<pre>@ element.++ Example:++ > pre $ span $ fmt "foo"++ Result:++ > <pre><span>foo</span></pre>+-}+pre ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+pre = element "pre"+{-# INLINE pre #-}++{- | Combinator for the @\<progress>@ element.++ Example:++ > progress $ span $ fmt "foo"++ Result:++ > <progress><span>foo</span></progress>+-}+progress ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+progress = element "progress"+{-# INLINE progress #-}++{- | Combinator for the @\<q>@ element.++ Example:++ > q $ span $ fmt "foo"++ Result:++ > <q><span>foo</span></q>+-}+q ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+q = element "q"+{-# INLINE q #-}++{- | Combinator for the @\<rp>@ element.++ Example:++ > rp $ span $ fmt "foo"++ Result:++ > <rp><span>foo</span></rp>+-}+rp ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+rp = element "rp"+{-# INLINE rp #-}++{- | Combinator for the @\<rt>@ element.++ Example:++ > rt $ span $ fmt "foo"++ Result:++ > <rt><span>foo</span></rt>+-}+rt ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+rt = element "rt"+{-# INLINE rt #-}++{- | Combinator for the @\<ruby>@ element.++ Example:++ > ruby $ span $ fmt "foo"++ Result:++ > <ruby><span>foo</span></ruby>+-}+ruby ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+ruby = element "ruby"+{-# INLINE ruby #-}++{- | Combinator for the @\<samp>@ element.++ Example:++ > samp $ span $ fmt "foo"++ Result:++ > <samp><span>foo</span></samp>+-}+samp ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+samp = element "samp"+{-# INLINE samp #-}++{- | Combinator for the @\<script>@ element.++ Example:++ > script $ span $ fmt "foo"++ Result:++ > <script><span>foo</span></script>+-}+script ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+script = element "script"+{-# INLINE script #-}++{- | Combinator for the @\<section>@ element.++ Example:++ > section $ span $ fmt "foo"++ Result:++ > <section><span>foo</span></section>+-}+section ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+section = element "section"+{-# INLINE section #-}++{- | Combinator for the @\<select>@ element.++ Example:++ > select $ span $ fmt "foo"++ Result:++ > <select><span>foo</span></select>+-}+select ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+select = element "select"+{-# INLINE select #-}++{- | Combinator for the @\<small>@ element.++ Example:++ > small $ span $ fmt "foo"++ Result:++ > <small><span>foo</span></small>+-}+small ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+small = element "small"+{-# INLINE small #-}++{- | Combinator for the @\<source />@ element.++ Example:++ > source++ Result:++ > <source />+-}+source ::+    -- | Resulting HTML.+    Html a+source = element_ "source"+{-# INLINE source #-}++{- | Combinator for the @\<span>@ element.++ Example:++ > span $ span $ fmt "foo"++ Result:++ > <span><span>foo</span></span>+-}+span ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+span = element "span"+{-# INLINE span #-}++{- | Combinator for the @\<strong>@ element.++ Example:++ > strong $ span $ fmt "foo"++ Result:++ > <strong><span>foo</span></strong>+-}+strong ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+strong = element "strong"+{-# INLINE strong #-}++{- | Combinator for the @\<style>@ element.++ Example:++ > style $ span $ fmt "foo"++ Result:++ > <style><span>foo</span></style>+-}+style ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+style = element "style"+{-# INLINE style #-}++{- | Combinator for the @\<sub>@ element.++ Example:++ > sub $ span $ fmt "foo"++ Result:++ > <sub><span>foo</span></sub>+-}+sub ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+sub = element "sub"+{-# INLINE sub #-}++{- | Combinator for the @\<summary>@ element.++ Example:++ > summary $ span $ fmt "foo"++ Result:++ > <summary><span>foo</span></summary>+-}+summary ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+summary = element "summary"+{-# INLINE summary #-}++{- | Combinator for the @\<sup>@ element.++ Example:++ > sup $ span $ fmt "foo"++ Result:++ > <sup><span>foo</span></sup>+-}+sup ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+sup = element "sup"+{-# INLINE sup #-}++{- | Combinator for the @\<table>@ element.++ Example:++ > table $ span $ fmt "foo"++ Result:++ > <table><span>foo</span></table>+-}+table ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+table = element "table"+{-# INLINE table #-}++{- | Combinator for the @\<tbody>@ element.++ Example:++ > tbody $ span $ fmt "foo"++ Result:++ > <tbody><span>foo</span></tbody>+-}+tbody ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+tbody = element "tbody"+{-# INLINE tbody #-}++{- | Combinator for the @\<td>@ element.++ Example:++ > td $ span $ fmt "foo"++ Result:++ > <td><span>foo</span></td>+-}+td ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+td = element "td"+{-# INLINE td #-}++{- | Combinator for the @\<textarea>@ element.++ Example:++ > textarea $ span $ fmt "foo"++ Result:++ > <textarea><span>foo</span></textarea>+-}+textarea ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+textarea = element "textarea"+{-# INLINE textarea #-}++{- | Combinator for the @\<tfoot>@ element.++ Example:++ > tfoot $ span $ fmt "foo"++ Result:++ > <tfoot><span>foo</span></tfoot>+-}+tfoot ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+tfoot = element "tfoot"+{-# INLINE tfoot #-}++{- | Combinator for the @\<th>@ element.++ Example:++ > th $ span $ fmt "foo"++ Result:++ > <th><span>foo</span></th>+-}+th ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+th = element "th"+{-# INLINE th #-}++{- | Combinator for the @\<thead>@ element.++ Example:++ > thead $ span $ fmt "foo"++ Result:++ > <thead><span>foo</span></thead>+-}+thead ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+thead = element "thead"+{-# INLINE thead #-}++{- | Combinator for the @\<time>@ element.++ Example:++ > time $ span $ fmt "foo"++ Result:++ > <time><span>foo</span></time>+-}+time ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+time = element "time"+{-# INLINE time #-}++{- | Combinator for the @\<title>@ element.++ Example:++ > title $ span $ fmt "foo"++ Result:++ > <title><span>foo</span></title>+-}+title ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+title = element "title"+{-# INLINE title #-}++{- | Combinator for the @\<tr>@ element.++ Example:++ > tr $ span $ fmt "foo"++ Result:++ > <tr><span>foo</span></tr>+-}+tr ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+tr = element "tr"+{-# INLINE tr #-}++{- | Combinator for the @\<track />@ element.++ Example:++ > track++ Result:++ > <track />+-}+track ::+    -- | Resulting HTML.+    Html a+track = element_ "track"+{-# INLINE track #-}++{- | Combinator for the @\<u>@ element.++ Example:++ > u $ span $ fmt "foo"++ Result:++ > <u><span>foo</span></u>+-}+u ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+u = element "u"+{-# INLINE u #-}++{- | Combinator for the @\<ul>@ element.++ Example:++ > ul $ span $ fmt "foo"++ Result:++ > <ul><span>foo</span></ul>+-}+ul ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+ul = element "ul"+{-# INLINE ul #-}++{- | Combinator for the @\<var>@ element.++ Example:++ > var $ span $ fmt "foo"++ Result:++ > <var><span>foo</span></var>+-}+var ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+var = element "var"+{-# INLINE var #-}++{- | Combinator for the @\<video>@ element.++ Example:++ > video $ span $ fmt "foo"++ Result:++ > <video><span>foo</span></video>+-}+video ::+    -- | Inner HTML.+    Html a ->+    -- | Resulting HTML.+    Html a+video = element "video"+{-# INLINE video #-}++{- | Combinator for the @\<wbr />@ element.++ Example:++ > wbr++ Result:++ > <wbr />+-}+wbr :: Html a+wbr = element_ "wbr"+{-# INLINE wbr #-}
+ src/Data/Fmt/Time.hs view
@@ -0,0 +1,106 @@+{-# LANGUAGE OverloadedStrings #-}++module Data.Fmt.Time (+    time,++    -- * Time+    t,+    hm,+    hms,+    day,+    day',+    month,+    month',+    year,+    unix,+    zone,++    -- * Duration+    secs,+    mins,+    hours,+    days,+    years,+) where++import Data.Fmt+import Data.String+import Data.Time (FormatTime, defaultTimeLocale, formatTime)+import Data.Time.Format.ISO8601 (ISO8601, iso8601Show)+import Prelude hiding (min)+import qualified Data.Fmt.Code as Fmt++{- | A custom time formatter.++ For example, the E.U. formatting convention is  /time "%Y-%m-%d %T %z"/+-}+time :: (IsString m, FormatTime a) => String -> Fmt1 m s a+time s = fmt1 $ fromString . formatTime defaultTimeLocale s++-- Time++-------------------------++-- | < https://en.wikipedia.org/wiki/ISO_8601 ISO-8601> time: /2021-06-05T01:46:46.173677-07:00/+t :: (IsString m, ISO8601 a) => Fmt1 m s a+t = fmt1 $ fromString . iso8601Show++-- | Hour-minute of day: @%H:%M@.+hm :: (IsString m, FormatTime a) => Fmt1 m s a+hm = time "%R"++-- | Hour-minute-second of day: @%H:%M:%S@.+hms :: (IsString m, FormatTime a) => Fmt1 m s a+hms = time "%T"++-- | Day of month: @01@ - @31@.+day :: (IsString m, FormatTime a) => Fmt1 m s a+day = time "%d"++-- | Day of week: @Sun@ - @Sat@.+day' :: (IsString m, FormatTime a) => Fmt1 m s a+day' = time "%a"++-- | Month of year: @01@ - @12@.+month :: (IsString m, FormatTime a) => Fmt1 m s a+month = time "%m"++-- | Month of year: @Jan@ - @Dec@.+month' :: (IsString m, FormatTime a) => Fmt1 m s a+month' = time "%b"++-- | Year.+year :: (IsString m, FormatTime a) => Fmt1 m s a+year = time "%Y"++-- | Seconds from Unix epoch.+unix :: (IsString m, FormatTime a) => Fmt1 m s a+unix = time "%s"++-- | Timezone offset: @-HHMM@.+zone :: (IsString m, FormatTime a) => Fmt1 m s a+zone = time "%z"++-- Duration++-------------------------++-- | Display to a given precision the absolute value time span in seconds.+secs :: IsString m => Int -> Fmt1 m s Double+secs n = fmt1 (runFmt (Fmt.f n) . abs . count) where count n' = n'++-- | Display to a given precision the absolute value time span in minutes.+mins :: IsString m => Int -> Fmt1 m s Double+mins n = fmt1 (runFmt (Fmt.f n) . abs . count) where count n' = n' / 60++-- | Display to a given precision the absolute value time span in hours.+hours :: IsString m => Int -> Fmt1 m s Double+hours n = fmt1 (runFmt (Fmt.f n) . abs . count) where count n' = n' / 60 / 60++-- | Display to a given precision the absolute value time span in days.+days :: (IsString m) => Int -> Fmt1 m s Double+days n = fmt1 (runFmt (Fmt.f n) . abs . count) where count n' = n' / 24 / 60 / 60++-- | Display to a given precision the absolute value time span in years.+years :: IsString m => Int -> Fmt1 m s Double+years n = fmt1 (runFmt (Fmt.f n) . abs . count) where count n' = n' / 365 / 24 / 60 / 60