packages feed

percent-format (empty) → 0.0.1

raw patch · 55 files changed

+3868/−0 lines, 55 filesdep +basedep +leancheckdep +percent-formatsetup-changed

Dependencies added: base, leancheck, percent-format

Files

+ .gitignore view
@@ -0,0 +1,38 @@+# .gitignore for PercentFormat++# General+**.swp+**~+etc/++# Haskell+**.hi+**.o+**.dyn_hi+**.dyn_o+**.hpc+**.hpc-*+**.tix++# Haskell Cabal+**/.cabal-sandbox+**/cabal.sandbox.config+**/dist/++# hasktags+**/idx/+**/TAGS+**/tags++# specific files and folders+doc+mk/toplibs+bench/examples+bench/speculate+tests/test-main+tests/test-number+tests/test-prop+tests/test-quotient+tests/test-spec+tests/test-unit+tests/test-scientific
+ .travis.yml view
@@ -0,0 +1,82 @@+# .travis.yml file for percent-format+#+# Copyright:   (c) 2018 Rudy Matela+# License:     3-Clause BSD  (see the file LICENSE)+# Maintainer:  Rudy Matela <rudy@matela.com.br>++language: c  # not really++notifications:+  email:+    on_failure: change++sudo: false++cache:+  directories:+  - $HOME/.ghc+  - $HOME/.cabal+  - $HOME/.stack++before_install:+- export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH+- ghc --version+- cabal --version+- rm -f ~/.cabal/config && cabal update+# Download and unpack the stack executable+# "Once Travis whitelists the stack.dev files," simply include stack in the+# addons section. -- https://docs.haskellstack.org/en/stable/travis_ci/+- mkdir -p ~/.local/bin+- export PATH=$HOME/.local/bin:$PATH+- travis_retry curl -L https://www.stackage.org/stack/linux-x86_64 | tar xz --wildcards --strip-components=1 -C ~/.local/bin '*/stack'+- stack config set system-ghc --global true+- stack --version+- cabal install leancheck++script:+- make && make test && make haddock HADDOCKFLAGS=+- make test-sdist+- cabal test+- stack --no-terminal --skip-ghc-check test++matrix:+  allow_failures:+  - ghc: 'head'+  include:+  - ghc: 'head'+    env:                   GHCVER=head         CABALVER=head+    addons: {apt: {packages: [ghc-head,   cabal-install-head], sources: hvr-ghc}}+  - ghc: '8.4'+    env:                   GHCVER=8.4.2        CABALVER=2.2+    addons: {apt: {packages: [ghc-8.4.2,  cabal-install-2.2],  sources: hvr-ghc}}+  - ghc: '8.2'+    env:                   GHCVER=8.2.2        CABALVER=2.0+    addons: {apt: {packages: [ghc-8.2.2,  cabal-install-2.0],  sources: hvr-ghc}}+  - ghc: '8.0'+    env:                   GHCVER=8.0.2        CABALVER=1.24+    addons: {apt: {packages: [ghc-8.0.2,  cabal-install-1.24], sources: hvr-ghc}}+  - ghc: '7.10'+    env:                   GHCVER=7.10.3       CABALVER=1.22+    addons: {apt: {packages: [ghc-7.10.3, cabal-install-1.22], sources: hvr-ghc}}+  # we only support stack with GHC >= 7.10+  - ghc: '7.8'+    env:                   GHCVER=7.8.4        CABALVER=1.18+    addons: {apt: {packages: [ghc-7.8.4,  cabal-install-1.18], sources: hvr-ghc}}+    before_install:+    - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH+    - ghc --version+    - cabal --version+    - rm -f ~/.cabal/config && cabal update+    - cabal install Cabal==1.18.*+    - cabal install leancheck+    script:+    - make && make test && make haddock HADDOCKFLAGS=+    - cabal test+# Hugs is not a GHC version.  But this is how travis can handle it.+  - ghc: 'hugs'+    env:                   GHCVER=hugs+    addons: {apt: {packages: [hugs]}}+    before_install:+    - echo ":version" | hugs+    script:+    - make hugs-test
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2016-2018, Rudy Matela++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * 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.++    * Neither the name of Rudy Matela nor the names of other+      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+OWNER 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.
+ Makefile view
@@ -0,0 +1,150 @@+# Makefile for percentformat+#+# Copyright:   (c) 2015-2018 Rudy Matela+# License:     3-Clause BSD  (see the file LICENSE)+# Maintainer:  Rudy Matela <rudy@matela.com.br>+TESTS = \+  tests/test-spec \+  tests/test-unit \+  tests/test-number \+  tests/test-scientific \+  tests/test-quotient \+  tests/test-prop+EGS =+BENCHS = bench/speculate+GHCIMPORTDIRS = src:tests+GHCFLAGS = -O2 $(shell grep -q "Arch Linux" /etc/lsb-release && echo -dynamic)+HADDOCKFLAGS = --no-print-missing-docs+HUGSIMPORTDIRS = .:./src:./tests:/usr/lib/hugs/packages/*++all: mk/toplibs $(TESTS)++test: $(patsubst %,%.test,$(TESTS)) diff-test++test-via-cabal:+	cabal clean  &&  cabal configure --enable-tests  && cabal test++test-via-stack:+	stack test++test-sdist:+	./tests/test-sdist++legacy-test: # needs ghc-8.0 .. ghc-7.8 installed as such+	make clean  &&  make test GHC=ghc-8.2  GHCFLAGS="-Werror -dynamic"+	make clean  &&  make test GHC=ghc-8.0  GHCFLAGS="-Werror -dynamic"+	make clean  &&  make test GHC=ghc-7.10 GHCFLAGS="-Werror -dynamic"+	make clean  &&  make test GHC=ghc-7.8  GHCFLAGS="-Werror -dynamic"+	make clean  &&  make test++legacy-test-via-cabal: # needs similarly named cabal wrappers+	cabal clean  &&  cabal-ghc-8.2  configure  &&  cabal-ghc-8.2  test+	cabal clean  &&  cabal-ghc-8.0  configure  &&  cabal-ghc-8.0  test+	cabal clean  &&  cabal-ghc-7.10 configure  &&  cabal-ghc-7.10 test+	cabal clean  &&  cabal-ghc-7.8  configure  &&  cabal-ghc-7.8  test+	cabal clean  &&  cabal test++prepare:+	cabal update  &&  cabal install leancheck++prepare-legacy-test:+	cabal-ghc-8.2  update  &&  cabal-ghc-8.2  install leancheck+	cabal-ghc-8.0  update  &&  cabal-ghc-8.0  install leancheck+	cabal-ghc-7.10 update  &&  cabal-ghc-7.10 install leancheck+	cabal-ghc-7.8  update  &&  cabal-ghc-7.8  install leancheck++hlint:+	hlint \+	  .++doctest:+	doctest -isrc src/Text/PercentFormat.hs++bench: $(BENCHS)+	./bench/speculate++%.test: %+	./$<++clean: clean-hi-o+	rm -f $(TESTS) $(EG) mk/toplibs+	rm -rf doc/++ghci: mk/All.ghci++hugs: mk/All.hugs++hugs-test: \+  tests/test-spec.runhugs \+  tests/test-unit.runhugs \+  tests/test-number.runhugs \+  tests/test-scientific.runhugs++diff-test: examples-diff-test++update-diff-test: update-examples-diff-test++examples-diff-test: bench/examples+	./bench/examples             | diff -rud tests/diff/examples.out         -+	./bench/examples "%r"        | diff -rud tests/diff/examples-r.out       -+	./bench/examples "%6r"       | diff -rud tests/diff/examples-6r.out      -+	./bench/examples "%-6r"      | diff -rud tests/diff/examples--6r.out     -+	./bench/examples "%s"        | diff -rud tests/diff/examples-s.out       -+	./bench/examples "%6s"       | diff -rud tests/diff/examples-6s.out      -+	./bench/examples "%-6s"      | diff -rud tests/diff/examples--6s.out     -+	./bench/examples "%i"        | diff -rud tests/diff/examples-i.out       -+	./bench/examples "%3i"       | diff -rud tests/diff/examples-3i.out      -+	./bench/examples "%03i"      | diff -rud tests/diff/examples-03i.out     -+	./bench/examples "%-3i"      | diff -rud tests/diff/examples--3i.out     -+	./bench/examples "%+3i"      | diff -rud tests/diff/examples-+3i.out     -+	./bench/examples "% 3i"      | diff -rud tests/diff/examples-_3i.out     -+	./bench/examples "%f"        | diff -rud tests/diff/examples-f.out       -+	./bench/examples "%5f"       | diff -rud tests/diff/examples-5f.out      -+	./bench/examples "%+5f"      | diff -rud tests/diff/examples-+5f.out     -+	./bench/examples "%-5f"      | diff -rud tests/diff/examples--5f.out     -+	./bench/examples "%11.2f"    | diff -rud tests/diff/examples-11p2f.out   -+	./bench/examples "%-11.2f"   | diff -rud tests/diff/examples--11p2f.out  -+	./bench/examples "%c"        | diff -rud tests/diff/examples-c.out       -+	./bench/examples "%2c"       | diff -rud tests/diff/examples-2c.out      -+	./bench/examples "%b"        | diff -rud tests/diff/examples-b.out       -+	./bench/examples "%o"        | diff -rud tests/diff/examples-o.out       -+	./bench/examples "%x"        | diff -rud tests/diff/examples-x.out       -+	./bench/examples "%X"        | diff -rud tests/diff/examples-X.out       -+	./bench/examples "abc"       | diff -rud tests/diff/examples-abc.out     -++update-examples-diff-test: bench/examples+	./bench/examples             > tests/diff/examples.out+	./bench/examples "%r"        > tests/diff/examples-r.out+	./bench/examples "%6r"       > tests/diff/examples-6r.out+	./bench/examples "%-6r"      > tests/diff/examples--6r.out+	./bench/examples "%s"        > tests/diff/examples-s.out+	./bench/examples "%6s"       > tests/diff/examples-6s.out+	./bench/examples "%-6s"      > tests/diff/examples--6s.out+	./bench/examples "%i"        > tests/diff/examples-i.out+	./bench/examples "%3i"       > tests/diff/examples-3i.out+	./bench/examples "%03i"      > tests/diff/examples-03i.out+	./bench/examples "%-3i"      > tests/diff/examples--3i.out+	./bench/examples "%+3i"      > tests/diff/examples-+3i.out+	./bench/examples "% 3i"      > tests/diff/examples-_3i.out+	./bench/examples "%f"        > tests/diff/examples-f.out+	./bench/examples "%5f"       > tests/diff/examples-5f.out+	./bench/examples "%+5f"      > tests/diff/examples-+5f.out+	./bench/examples "%-5f"      > tests/diff/examples--5f.out+	./bench/examples "%11.2f"    > tests/diff/examples-11p2f.out+	./bench/examples "%-11.2f"   > tests/diff/examples--11p2f.out+	./bench/examples "%c"        > tests/diff/examples-c.out+	./bench/examples "%2c"       > tests/diff/examples-2c.out+	./bench/examples "%b"        > tests/diff/examples-b.out+	./bench/examples "%o"        > tests/diff/examples-o.out+	./bench/examples "%x"        > tests/diff/examples-x.out+	./bench/examples "%X"        > tests/diff/examples-X.out+	./bench/examples "abc"       > tests/diff/examples-abc.out++# NOTE: (very hacky!) the following target allows parallel compilation (-jN) of+# eg and tests programs so long as they don't share dependencies _not_ stored+# in src/ and tests/.  Runnable binaries should depend on mk/toplibs instead of+# actual Haskell source files+mk/toplibs: mk/Toplibs.o+	touch mk/toplibs++include mk/haskell.mk
+ README.md view
@@ -0,0 +1,49 @@+PercentFormat -- C-like printf-style string formatting for Haskell+==================================================================++The `Text.PercentFormat` library provides printf-style string formatting.  It+provides a `%` operator (as in Ruby or Python) and uses the old C-printf-style+format you know and love.++This library differs from `Text.Printf` in that it does not rely on custom+typeclasses -- it works on anything that is a `Show` instance.++Formatting one value:++	> import Text.PercentFormat+	> "Hello %s!" -% "World"+	"Hello World!"++Formatting three values, tuple style:++	> "load average: %1.2f %1.2f %1.2f" -%%% (0.00, 0.066, 0.11)+	"load average: 0.00 0.07 0.11"++Formatting three values, chain style:++	> "load average: %1.2f %1.2f %1.2f" % 0.00 % 0.066 -% 0.11+	"load average: 0.00 0.07 0.11"+++To produce a string with a percent sign (`%`),+use two percent signs (`%%`):++	> "memory usage: %i%%" -% 13+	"memory usage: 13%"+++Percent signs are duplicated when using the `%` operator to allow chaining:++	> "percent sign: %s, memory usage: %i%%" % "%" % 87+	"percent sign: %%, memory usage: 87%%"++_Always_ use the `-%` operator when formatting the _last value_+to remove duplicate `%` signs:++	> "percent sign: %s, memory usage: %i%%" % "%" -% 87+	"percent sign: %, memory usage: 87%"++To print, just prefix you format expression with `putStrLn $`:++	> putStrLn $ "Hello %s!" -% "World"+	Hello World!
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ TODO.md view
@@ -0,0 +1,31 @@+TO DO list for PercentFormat+============================++TO DO list for PercentFormat, more or less in order:++* when `%s` argument is char, generate `<char>` instead of `'<char>'`;++* when `%i`/`%f`/etc argument is a number encoded in a string, parse the number+  and make it work;++* add `%e`;++* release percent-format package on Hackage;++* add link to Haddock documentation on README;++* add `%q` (see `tests/test-number.hs`);++* sweep `TODO`s scattered through files;++* *maybe*: make "%l" for lists:++    > "%l" % [1,2,3] -- regular+    [1,2,3]+    > "% l" % [1,2,3] -- add spaces+    [1, 2, 3]+    > "%\nl" % [1,2,3] -- add linebreaks+    [ 1+    , 2+    , 3 ]+
+ bench/examples.hs view
@@ -0,0 +1,28 @@+-- Copyright (c) 2018 Rudy Matela.+-- Distributed under the 3-Clause BSD licence (see the file LICENSE).+import Text.PercentFormat+import Test.LeanCheck+import System.Environment (getArgs)++put :: String -> IO ()+put s  =  putStrLn . unlines+       $  (s %&) `map` take 12 (list :: [String])+       ++ (s %&) `map` take 12 (list :: [Int])+       ++ (s %&) `map` take 12 (list :: [Float])+       ++ (s %&) `map` take 12 (list :: [Rational])+       ++ (s %&) `map` take 12 (list :: [Char])+       ++ (s %&) `map` take 12 (list :: [Bool])++main :: IO ()+main = do+  as <- getArgs+  let s = case as of+          [] -> "%r"+          (s:_) -> s+  put s++(%&) :: Show a => String -> a -> String+s %& x = "%r -%% %12-s == %r" % s % show11 x -% (s -% x)++show11 :: Show a => a -> String+show11 x = showsPrec 11 x ""
+ bench/speculate.hs view
@@ -0,0 +1,17 @@+-- Copyright (c) 2018 Rudy Matela.+-- Distributed under the 3-Clause BSD licence (see the file LICENSE).+import Test.Speculate+import Text.PercentFormat++-- TODO: make this work by tweaking the String enumeration+main :: IO ()+main = speculate args+  { maxTests = 100000+  , constants =+      [ constant "%"   ((%)   ->:> int)+      , constant "-%"  ((-%)  ->:> int)+--    , constant "%%"  ((%%)  ->:> (int,int))+--    , constant "-%%" ((-%%) ->:> (int,int))+      , constant "/%"  (/%)+      ]+  }
+ mk/All.hs view
@@ -0,0 +1,12 @@+module All+  ( module Text.PercentFormat+  , module Text.PercentFormat.Spec+  , module Text.PercentFormat.Utils+  , module Text.PercentFormat.Quotient+  )+where++import Text.PercentFormat+import Text.PercentFormat.Spec hiding (leftAlign)+import Text.PercentFormat.Utils+import Text.PercentFormat.Quotient hiding ((%))
+ mk/Toplibs.hs view
@@ -0,0 +1,5 @@+-- Using ghc --make in this module triggers compilation of every library.+module Toplibs () where++import Text.PercentFormat ()+import Text.PercentFormat.Spec ()
+ mk/depend.mk view
@@ -0,0 +1,104 @@+bench/examples: \+  bench/examples.hs \+  mk/toplibs+bench/examples.o: \+  src/Text/PercentFormat/Utils.hs \+  src/Text/PercentFormat/Spec.hs \+  src/Text/PercentFormat/Quotient.hs \+  src/Text/PercentFormat.hs \+  bench/examples.hs+bench/speculate: \+  bench/speculate.hs \+  mk/toplibs+bench/speculate.o: \+  src/Text/PercentFormat/Utils.hs \+  src/Text/PercentFormat/Spec.hs \+  src/Text/PercentFormat/Quotient.hs \+  src/Text/PercentFormat.hs \+  bench/speculate.hs+mk/All.o: \+  src/Text/PercentFormat/Utils.hs \+  src/Text/PercentFormat/Spec.hs \+  src/Text/PercentFormat/Quotient.hs \+  src/Text/PercentFormat.hs \+  mk/All.hs+mk/Toplibs.o: \+  src/Text/PercentFormat/Utils.hs \+  src/Text/PercentFormat/Spec.hs \+  src/Text/PercentFormat/Quotient.hs \+  src/Text/PercentFormat.hs \+  mk/Toplibs.hs+src/Text/PercentFormat: \+  mk/toplibs+src/Text/PercentFormat.o: \+  src/Text/PercentFormat/Utils.hs \+  src/Text/PercentFormat/Spec.hs \+  src/Text/PercentFormat/Quotient.hs \+  src/Text/PercentFormat.hs+src/Text/PercentFormat/Quotient.o: \+  src/Text/PercentFormat/Quotient.hs+src/Text/PercentFormat/Spec.o: \+  src/Text/PercentFormat/Spec.hs+src/Text/PercentFormat/Utils.o: \+  src/Text/PercentFormat/Utils.hs+tests/test-number.o: \+  tests/Test.hs \+  tests/test-number.hs \+  src/Text/PercentFormat/Utils.hs \+  src/Text/PercentFormat/Spec.hs \+  src/Text/PercentFormat/Quotient.hs \+  src/Text/PercentFormat.hs+tests/test-number: \+  tests/Test.hs \+  tests/test-number.hs \+  mk/toplibs+tests/Test.o: \+  tests/Test.hs \+  src/Text/PercentFormat/Utils.hs \+  src/Text/PercentFormat/Spec.hs \+  src/Text/PercentFormat/Quotient.hs \+  src/Text/PercentFormat.hs+tests/test-prop.o: \+  tests/test-prop.hs \+  tests/Test.hs \+  src/Text/PercentFormat/Utils.hs \+  src/Text/PercentFormat/Spec.hs \+  src/Text/PercentFormat/Quotient.hs \+  src/Text/PercentFormat.hs+tests/test-prop: \+  tests/test-prop.hs \+  tests/Test.hs \+  mk/toplibs+tests/test-quotient.o: \+  tests/test-quotient.hs \+  tests/Test.hs \+  src/Text/PercentFormat/Utils.hs \+  src/Text/PercentFormat/Spec.hs \+  src/Text/PercentFormat/Quotient.hs \+  src/Text/PercentFormat.hs+tests/test-quotient: \+  tests/test-quotient.hs \+  tests/Test.hs \+  mk/toplibs+tests/test-spec.o: \+  tests/test-spec.hs \+  tests/Test.hs \+  src/Text/PercentFormat/Utils.hs \+  src/Text/PercentFormat/Spec.hs \+  src/Text/PercentFormat/Quotient.hs \+  src/Text/PercentFormat.hs+tests/test-spec: \+  tests/test-spec.hs \+  tests/Test.hs \+  mk/toplibs+tests/test-unit.o: \+  tests/test-unit.hs \+  tests/Test.hs \+  src/Text/PercentFormat/Utils.hs \+  src/Text/PercentFormat/Spec.hs \+  src/Text/PercentFormat/Quotient.hs \+  src/Text/PercentFormat.hs+tests/test-unit: \+  tests/test-unit.hs \+  tests/Test.hs \+  mk/toplibs
+ mk/ghcdeps view
@@ -0,0 +1,49 @@+#!/bin/bash+#+# ghcdeps: generate Haskell make dependencies for compiling with GHC.+#+# Copyright (c) 2015-2017 Rudy Matela.+# Distributed under the 3-Clause BSD licence.+#+# From a list of files provided on standard input,+# generate flat make dependencies.+#+# Transitive relations are repeated.+#+# Usage:+#   $ ghcdeps -isomedir:someother <<LIST+#   program.hs+#   Library.hs+#   Path/To/Library.hs+#   LIST+#   program: ...+#   Library.o: ...+#   Path/To/Library.o: ...+#+# Or:+#   $ find -name \*.hs -o -name \*.lhs | ghcdeps [GHCFLAGS]+#   ...+#+# Note that when using find, you have to remember to exclude unecessary files,+# e.g.:  dist, Setup.hs+#+# Yes, this is hacky.  But hey, it works.+while read fn+do+	ghc "$@" -dep-suffix=. -dep-makefile=tmp.mk -M "$fn" ||+	exit 1+	deps="`cat tmp.mk |+	       grep "hs$" |+	       sort |+	       sed -e "s/.*: //" |+	       tac |+	       tr '\n' ' ' |+	       sed -e "s/ $//"`"+	obj=`echo $fn | sed -e 's,^\./,,;s/\.hs$/.o/'`+	bin=`echo $fn | sed -e 's,^\./,,;s/\.hs$//'`+	echo "$obj: $deps"+	grep -q "main" "$fn" && echo "$bin: `echo $deps | sed -e 's|[^ ]*src[^ ]*||g'` mk/toplibs"+	rm -f tmp.mk+done |+sort |+sed -e 's,  *, \\\n  ,g'
+ mk/haddock-i view
@@ -0,0 +1,24 @@+#!/bin/bash+#+# haddock-i: list haddock's -i parameters.+#+# Copyright (c) 2015-2017 Rudy Matela.+# Distributed under the 3-Clause BSD licence.+#+# $ haddock-i <package1> <package2> ... <packageN>+#+# will print -i parameters necessary for haddock to link to Haddock+# documentation installed on your system, so you can:+#+# $ haddock-i base template-haskell | xargs haddock <files>+errxit() {+	echo "$@" > /dev/stderr+	exit 1+}++for pkg in "$@"; do+	ghc-pkg field $pkg haddock-html,haddock-interfaces ||+	errxit "error: haddock-i: cannot find package $pkg (ghc-pkg)"+done |+sed "s/.*: //" |+sed "N;s/\n/,/;s/^/-i/"
+ mk/haskell.mk view
@@ -0,0 +1,110 @@+# Implicit rules for compiling Haskell code.+#+# Copyright (c) 2015-2018 Rudy Matela.+# Distributed under the 3-Clause BSD licence.+#+# You can optionally configure the "Configuration variables" below in your main+# makefile, e.g.:+#+#   GHCIMPORTDIRS = path/to/dir:path/to/another/dir+#   GHCFLAGS = -O2 -dynamic+#   GHC = ghc-7.6+#   include haskell.mk++++# Configuration variables++# GHC Parameters+GHCIMPORTDIRS ?=+GHCFLAGS ?=+GHC ?= ghc+GHCCMD = $(GHC) -i$(GHCIMPORTDIRS) $(GHCFLAGS)++# Hugs Parameters+HUGSIMPORTDIRS ?= "/usr/lib/hugs/packages/*"+HUGSFLAGS ?=+CPPHS_HUGS ?= cpphs-hugs --noline -D__HUGS__+HUGS ?= hugs+RUNHUGS ?= runhugs+HUGSCMD    = $(HUGS)    -F"$(CPPHS_HUGS)" -P$(HUGSIMPORTDIRS) $(HUGSFLAGS)+RUNHUGSCMD = $(RUNHUGS) -F"$(CPPHS_HUGS)" -P$(HUGSIMPORTDIRS) $(HUGSFLAGS)+++# Makefile where to keep the dependencies+DEPMK ?= mk/depend.mk++# LIB_HSS: all library Haskell files+# ALL_HSS: all Haskell files+# You can override ALL/LIB_HSS in your main Makefile+LIST_LIB_HSS ?= find src -name "*.hs"+LIST_ALL_HSS ?= find \( -path "./dist" -o -path "./.stack-work" \) -prune \+                     -o -name "*.*hs" -print+LIB_HSS ?= $(shell $(LIST_LIB_HSS))+ALL_HSS ?= $(shell $(LIST_ALL_HSS))++PKGNAME = $(shell cat *.cabal | grep "^name:"    | sed -e "s/name: *//")+++# Implicit rules+%.hi %.o: %.hs+	$(GHCCMD) $< && touch $@++%: %.hs+	$(GHCCMD) $< && touch $@++.PHONY: %.ghci+%.ghci: %.hs+	$(GHCCMD) -O0 --interactive $<++.PHONY: %.hugs+%.hugs: %.hs+	$(HUGSCMD) $<++.PHONY: %.runhugs+%.runhugs: %.hs+	$(RUNHUGSCMD) $<+++# Cleaning rule (add as a clean dependency)+.PHONY: clean-hi-o+clean-hi-o:+	find $(ALL_HSS) | sed -e 's/hs$$/o/'      | xargs rm -f+	find $(ALL_HSS) | sed -e 's/hs$$/hi/'     | xargs rm -f+	find $(ALL_HSS) | sed -e 's/hs$$/dyn_o/'  | xargs rm -f+	find $(ALL_HSS) | sed -e 's/hs$$/dyn_hi/' | xargs rm -f+++# Update dependency file+.PHONY: depend+depend:+	find $(ALL_HSS) | ./mk/ghcdeps -i$(GHCIMPORTDIRS) $(GHCFLAGS) > $(DEPMK)++# haddock rules+haddock: doc/index.html++clean-haddock:+	rm -f doc/*.{html,css,js,png,gif,json} README.html++upload-haddock:+	@echo "use \`cabal upload -d' instead"+	@echo "(but 1st: cabal install --only-dependencies --enable-documentation)"+	@echo "(to just compile docs: cabal haddock --for-hackage)"+	@echo "(on Arch Linux, use: cabal haddock --for-hackage --haddock-options=--optghc=-dynamic)"++doc/index.html: $(LIB_HSS)+	./mk/haddock-i base template-haskell | xargs \+	haddock --html -odoc $(LIB_HSS) $(HADDOCKFLAGS) --title=$(PKGNAME)++# lists all Haskell source files+list-all-hss:+	@find $(ALL_HSS)++# lists library Haskell source files+list-lib-hss:+	@find $(LIB_HSS)++show-pkgname:+	@echo $(PKGNAME)++include $(DEPMK)
+ percent-format.cabal view
@@ -0,0 +1,103 @@+-- Cabal file for PercentFormat++name:                percent-format+version:             0.0.1+synopsis:            simple printf-style string formatting+description:+  The @Text.PercentFormat@ library provides printf-style string formatting.  It+  provides a @%@ operator (as in Ruby or Python) and uses the old+  C-printf-style format you know and love.++homepage:            https://github.com/rudymatela/percent-format#readme+license:             BSD3+license-file:        LICENSE+author:              Rudy Matela <rudy@matela.com.br>+maintainer:          Rudy Matela <rudy@matela.com.br>+category:            Testing+build-type:          Simple+cabal-version:       1.18++extra-doc-files: README.md+               , TODO.md+extra-source-files: .gitignore+                  , Makefile+                  , mk/depend.mk+                  , mk/ghcdeps+                  , mk/haddock-i+                  , mk/All.hs+                  , mk/haskell.mk+                  , mk/Toplibs.hs+                  , stack.yaml+                  , tests/test-sdist+                  , .travis.yml+                  , bench/examples.hs+                  , bench/speculate.hs+                  , tests/diff/*.out+tested-with: GHC==8.4, GHC==8.2, GHC==8.0, GHC==7.10, GHC==7.8+++source-repository head+  type:            git+  location:        https://github.com/rudymatela/percent-format++source-repository this+  type:            git+  location:        https://github.com/rudymatela/percent-format+  tag:             v0.0.1++library+  exposed-modules: Text.PercentFormat+                 , Text.PercentFormat.Quotient+                 , Text.PercentFormat.Spec+                 , Text.PercentFormat.Utils+  hs-source-dirs:      src+  build-depends:       base >= 4 && < 5+  default-language:    Haskell2010++test-suite number+  type:                exitcode-stdio-1.0+  main-is:             test-number.hs+  other-modules:       Test+  hs-source-dirs:      tests+  build-depends:       base >= 4 && < 5, percent-format, leancheck+  default-language:    Haskell2010++test-suite scientific+  type:                exitcode-stdio-1.0+  main-is:             test-scientific.hs+  other-modules:       Test+  hs-source-dirs:      tests+  build-depends:       base >= 4 && < 5, percent-format, leancheck+  default-language:    Haskell2010++test-suite prop+  type:                exitcode-stdio-1.0+  main-is:             test-prop.hs+  other-modules:       Test+  hs-source-dirs:      tests+  build-depends:       base >= 4 && < 5, percent-format, leancheck+  default-language:    Haskell2010++test-suite quotient+  type:                exitcode-stdio-1.0+  main-is:             test-quotient.hs+  other-modules:       Test+  hs-source-dirs:      tests+  build-depends:       base >= 4 && < 5, percent-format, leancheck+  default-language:    Haskell2010++test-suite unit+  type:                exitcode-stdio-1.0+  main-is:             test-unit.hs+  other-modules:       Test+  hs-source-dirs:      tests+  build-depends:       base >= 4 && < 5, percent-format, leancheck+  default-language:    Haskell2010++test-suite spec+  type:                exitcode-stdio-1.0+  main-is:             test-spec.hs+  other-modules:       Test+  hs-source-dirs:      tests+  build-depends:       base >= 4 && < 5, percent-format, leancheck+  default-language:    Haskell2010
+ src/Text/PercentFormat.hs view
@@ -0,0 +1,517 @@+-- |+-- Module      : Text.PercentFormat+-- Copyright   : (c) 2016-2018 Rudy Matela+-- License     : 3-Clause BSD  (see the file LICENSE)+-- Maintainer  : Rudy Matela <rudy@matela.com.br>+--+-- The "Text.PercentFormat" library provides printf-style string formatting.+-- It provides a '%' operator (as in Ruby or Python)+-- and uses the old C-printf-style format you know and love.+--+-- This library differs from "Text.Printf" in that it does not rely on custom+-- typeclasses -- it works on anything that is a 'Show' instance that produces+-- output in the supported formats.+--+--+-- Formatting one value with '-%':+--+-- > > "Hello %s!" -% "World"+-- > "Hello World!"+--+--+-- Formatting three values, tuple style, with '-%%%':+--+-- > > "load average: %1.2f %1.2f %1.2f" -%%% (0.00, 0.066, 0.11)+-- > "load average: 0.00 0.07 0.11"+--+--+-- Formatting three values, chain style, with '%' and '-%':+--+-- > > "load average: %1.2f %1.2f %1.2f" % 0.00 % 0.066 -% 0.11+-- > "load average: 0.00 0.07 0.11"+--+--+-- To produce a string with a percent sign (@%@),+-- use two percent signs (@%%@):+--+-- > > "memory usage: %i%%" -% 13+-- > "memory usage: 13%"+--+--+-- Percent signs are duplicated when using the '%' operator to allow chaining+-- (further formats):+--+-- > > "percent sign: %s, memory usage: %i%%" % "%" % 87+-- > "percent sign: %%, memory usage: 87%%"+--+-- /Always/ use the '-%' operator when formatting the /last value/+-- to remove duplicate @%@ signs:+--+-- > > "percent sign: %s, memory usage: %i%%" % "%" -% 87+-- > "percent sign: %, memory usage: 87%"+--+-- To print, just prefix you format expression with "@putStrLn $@":+--+-- > > putStrLn $ "Hello %s!" -% "World"+-- > Hello World!+--+--+-- == Supported formats+--+-- * /r/ -- 'show' representation as-is (including quotes for strings).+--+--     > > "%r" % "string"+--     > "\"string\""+--+--     > > "%r" % Just 10+--     > "Just 10"+--+-- * /s/ -- string.  If the argument is 'show'ed as a 'String', intersperse it,+--          otherwise include representation in whole.+--+--     > > "%s" % "string"+--     > "string"+--+--     > > "%s" % 10+--     > "10"+--+--     > > "%s" % Just "string"+--     > "Just \"string\""+--+-- * /c/ -- Argument is converted to a single character.+--   Accepts arguments that when 'show'ed are represented as 'Char's.+--+--     > > "%c" % 'a'+--     > "a"+--+-- * /i/ -- Argument is converted to the nearest decimal integer.+--   Accepts arguments that when 'show'ed are represented as either+--   'Integer's, 'Rational's or 'Double's.+--+--     > > "%i" % 5040+--     > 5040+--+--     > > "%i" % 3.141+--     > 3+--+-- * /d/ -- Argument is converted to a decimal integer.+--   Accepts arguments that when 'show'ed are represented as either+--   'Integer's, 'Rational's or 'Double's.+--+--     > > "%d" % 5040+--     > 5040+--+--     > > "%i" % 3.141+--     > 3.141+--+-- * /x/ -- Argument is converted to hexadecimal format with lowercase letters.+--   Accepts arguments that when 'show'ed are represented as either+--   'Integer's, 'Rational's or 'Double's.+--+--     > > "%x" % 5040+--     > "13b0"+--+--     Differently from C's @printf@, negative integers are printed prefixed with+--     a minus (@-@) sign:+--+--     > > "%x" % (-5040)+--     > "-13b0"+--+--     Differently from C's @printf@, this library is able to show hexadecimal+--     fractional parts:+--+--     > > "%.6x" % pi+--     > "3.243f6b"+--+-- * /X/ -- Argument is converted to hexadecimal format with capital letters.+--   Accepts arguments that when 'show'ed are represented as either+--   'Integer's, 'Rational's or 'Double's.+--+--     > > "%X" % 5040+--     > "13B0"+--+-- * /o/ -- Argument is converted to octal format.+--   Accepts arguments that when 'show'ed are represented as either+--   'Integer's, 'Rational's or 'Double's.+--+--     > > "%o" % 5040+--     > "11660"+--+--     > > "%.6o" % pi+--     > "3.110376"+--+-- * /b/ -- Argument is converted to binary format.+--   Accepts arguments that when 'show'ed are represented as either+--   'Integer's, 'Rational's or 'Double's.+--+--     > > "%b" % 5040+--     > "1001110110000"+--+--     > > "%.6b" % pi+--     > "11.001001"+--+-- * /f/ -- Argument is converted to decimal format with a fractional part+--   (even when the given argument is an integer).+--   Accepts arguments that when 'show'ed are represented as either+--   'Integer's, 'Rational's or 'Double's.+--+--     > > "%f" % 5040+--     > "5040.0"+--+--     > > "%f" % pi+--     > "3.141592653589793"+--+-- * /e/ -- Argument is converted to scientific notation.+--       __This does not work yet.  To be added in a future version.__+--+-- * /q/ -- Argument is converted to a rational number.+--       __This does not work yet.  To be added in a future version.__+--+--+-- == Supported flag charaters+--+-- * /0/ -- the numeric value should be padded by zeros.+--+--     > > "%08i" % 5040+--     > "00005040"+--+-- * /-/ -- left adjusted values.+--+--     > > "%-8i" % 5040+--     > "5040    "+--+-- * / / -- leave a blank before a positive number.+--+--     > > "% i" % 5040+--     > " 5040"+--+--     > > "% i" % (-5040)+--     > "-5040"+--+-- * /+/ -- leave a plus sign before a positive number.+--+--     > > "%+i" % 5040+--     > "+5040"+--+--     > > "%+i" % (-5040)+--     > "-5040"+--+-- * /[1-9][0-9]*/ -- minimum field width.+--+--     > > "%8i" % 5040+--     > "    5040"+--+-- * /.[0-9][0-9]*/ -- precision.+--+--     > > "%.2i" % 5040+--     > "5040.00"+--+--     > > "%9.2i" % 5040+--     > "  5040.00"+--+--+-- == How does it work?+--+-- "Text.PercentFormat" works on values that are 'Show' instances producing+-- results in the expected format.  Take for example the following number type:+--+-- > data Digit = Zero | One | Two | Three+-- > instance Show Digit where+-- >   show Zero   =  "0"+-- >   show One    =  "1"+-- >   show Two    =  "2"+-- >   show Three  =  "3"+--+-- "Text.PercentFormat" works fine on it:+--+-- > > "%d %i %f %.2f" Zero One Two Three+-- > "0 1 2 3.00"+--+-- Because when 'show'ed, values of this @Digit@ type are represented as 'Integer's.+--+--+-- == Error Handling+--+-- This library is designed to avoid raising errors.+-- If conversion cannot be performed an exclamation mark (@!@) is produced.+-- If there are missing format strings an interrogation mark (@?@) is produced.+-- For example:+--+-- > > "%d %d" -% "Ten"+-- > "! ?"+--+-- The only two instances where errors are raised are:+--+-- 1. the argument values contain errors themselves:+--+--     > > "Hello %s!" % error "err"+--     > *** Exception err+--+--     > > error "err" % "World"+--     > *** Exception err+--+-- 2. the format string is not supported:+--+--     > > "%j" % 10+--     > *** Exception: unknown format string `j'+--+--+-- == Known bugs+--+-- * @"%x" % 3.1415926@ takes too long to run.+--+-- * @"%x" % pi@ takes /very very long/ to run.+module Text.PercentFormat+  ( (%)+  , (-%)+  , (/%)++  , (%%)+  , (%%%)+  , (%%%%)+  , (%%%%%)+  , (%%%%%%)++  , (-%%)+  , (-%%%)+  , (-%%%%)+  , (-%%%%%)+  , (-%%%%%%)++  , (+%)+  )+where++import Data.Maybe (listToMaybe, fromMaybe)+import Data.Char (isDigit, toUpper)+import Text.PercentFormat.Spec  as S+import Text.PercentFormat.Utils hiding (align)+import Text.PercentFormat.Quotient (maybeReadQ, digits, Quotient, infinity, nan)+import qualified Text.PercentFormat.Quotient as Q+import qualified Text.PercentFormat.Utils as U+import Prelude hiding (showString, showChar)++-- | Formats a single value into a string without finalizing:+--   leaving duplicate percent signs & remaining format sequences.+--+-- > > "Hello %s!" % "World"+-- > "Hello World!"+--+-- > > "processor usage: %d%%" % 67+-- > "processor usage: 67%%"+--+-- > > "load avg: %.2f %.2f %.2f" % 0.666+-- > "load avg: %0.67 %.2f %.2f"+--+-- Please use '-%' when formatting the last value into a string so that+-- duplicate percent signs are removed.+(%) :: Show a => String -> a -> String+('%':s) % x =+  case ty sp of+  Percent     -> '%':'%': s' % x+  ReprSpec    -> (duplicatePercents $ showRepr    sp x) ++ s'+  StringSpec  -> (duplicatePercents $ showString  sp x) ++ s'+  CharSpec    -> (duplicatePercents $ showChar    sp x) ++ s'+  NumberSpec  -> (duplicatePercents $ showDigits  sp x) ++ s'+  where+  (sp,s') = parseSpec s+(c:s)       % x = c : s % x+""          % x = ""+infixl 9 %++showRepr :: Show a => Spec -> a -> String+showRepr spec = align spec . show++showString :: Show a => Spec -> a -> String+showString spec s =+  case maybeRead (show s) of+  Nothing -> align spec (show s)+  Just s  -> align spec s++showChar :: Show a => Spec -> a -> String+showChar spec c =+  case maybeRead (show c) of+  Nothing -> err '!' spec+  Just c  -> align spec (c:"")++-- TODO: refactor showDigits (currently very hacky)+showDigits :: Show a => Spec -> a -> String+showDigits spec x =+  case maybeReadQ (show x) of+  Nothing -> err '!' spec+  Just q -> applyWhen (padWith spec /= ' ') (signal q ++)+          . align' q+          . applyWhen (padWith spec == ' ') (signal q ++)+          . either id (\(ids,fds,pds) -> capitalize $ showds ids fds pds (precision spec))+          . digits (base spec)+          . round' (base spec) (precision spec)+          $ q+  where+  capitalize = applyWhen (capitalizeDigits spec) (map toUpper)+  signal q | q >= 0 = positivePrefix spec+           | q <  0 = "-"+  align' :: Quotient -> String -> String+  align' q = if padWith spec == ' '+               then align spec+               else align spec{width = width spec - length (signal q)}+  round' :: Int -> Maybe Int -> Quotient -> Quotient+  round' _ _ q | Q.isInfinite q = q+  round' _ _ q | Q.isNaN q      = q+  round' _ Nothing  q = q+  round' b (Just p) q = round (q * fromIntegral b ^ p) Q.% fromIntegral b ^ p+  showds :: [Int] -> [Int] -> [Int] -> Maybe Int -> String+  showds ids fds []  Nothing  | length fds < minPrecision spec+                            = showds ids (fds ++ replicate (minPrecision spec - length fds) 0) [] Nothing+  showds ids []  _   Nothing  = intsToDigits ids+  showds ids fds pds (Just 0) = intsToDigits ids+  showds ids fds pds Nothing  = intsToDigits ids ++ "."+                             ++ intsToDigits fds ++ showPeriod pds+  showds ids fds pds (Just pr) = intsToDigits ids ++ "."+                              ++ intsToDigits (take pr (fds ++ loop pds ++ repeat 0))+  showPeriod [] = ""+  showPeriod xs = intsToDigits xs+               ++ intsToDigits xs+               ++ intsToDigits xs+               ++ "..."++err :: Char -> Spec -> String+err c spec = align spec{padWith=c} (c:"")++-- | Formats the last value into a string.+--   This finalizes formatting, removing duplicate percent signs and replacing+--   remaining format sequences with interrogation marks.+--+-- > > "Hello %s!" -% "World"+-- > "Hello World!"+--+-- > > "processor usage: %d%%" -% 67+-- > "processor usage: 67%"+--+-- > > "load avg: %.2f %.2f %.2f" % 0.666+-- > "load avg: %0.67 ? ?"+--+-- Please use '%' if you intend to further format values (chaining).+(-%) :: Show a => String -> a -> String+s -% x = s % x /% '?'+infixl 9 -%++-- | Replaces "%%" by "%".  Any remaining occurrences of format strings are+--   replaced by the given error character.  Field width is respected when+--   possible.+--+-- > > "100%% %i" /% '?'+-- > "100% ?"+--+-- > > "100%% %03i" /% '?'+-- > "100% ???"+(/%) :: String -> Char -> String+s /% errChar = depercent s+  where+  depercent ('%':s) = let (spec,s') = parseSpec s+                          s'' = case ty spec of+                                Percent     -> "%"+                                _           -> err errChar spec+                      in s'' ++ depercent s'+  depercent (c:s) = c : depercent s+  depercent "" = ""++-- | Aligns a string following a given spec.+--+-- > align spec{width=1} "asdf"+-- "asdf"+-- > align spec{width=5} "asdf"+-- " asdf"+-- > align spec{width=5, leftAlign=True} "asdf"+-- "asdf "+align :: Spec -> String -> String+align spec = U.align (S.leftAlign spec) (padWith spec) (width spec)++duplicatePercents :: String -> String+duplicatePercents ('%':s) = '%':'%':duplicatePercents s+duplicatePercents (c:s)   = c:duplicatePercents s+duplicatePercents ""      = ""++-- | Formats two values into a string without finalizing:+--   leaving duplicate percent signs & remaining format sequences.+--+-- > > "%s %s!" %% ("Hello","World")+-- > "Hello World!"+--+-- > > "load avg: %.2f %.2f %.2f" %% (0.666,0.333)+-- > "load avg: %0.67 %0.33 %.2f"+--+-- In general:+--+-- > s %% (x,y) == s % x % y+--+-- Please use '-%%' if you don't intend to format values into a string any further.+(%%) :: (Show a, Show b) => String -> (a,b) -> String+s %% (x,y) = s % x % y++-- | Formats three values into a string without finalizing.+--+-- > > "load avg: %.2f %.2f %.2f" %%% (0.666,0.333,0.1)+-- > "load avg: %0.67 %0.33 %0.10"+(%%%) :: (Show a, Show b, Show c) => String -> (a,b,c) -> String+s %%% (x,y,z) = s % x % y % z++-- | Formats four values into a string without finalizing.+(%%%%) :: (Show a, Show b, Show c, Show d) => String -> (a,b,c,d) -> String+s %%%% (x,y,z,w) = s % x % y % z % w++-- | Formats five values into a string without finalizing.+(%%%%%) :: (Show a, Show b, Show c, Show d, Show e)+        => String -> (a,b,c,d,e) -> String+s %%%%% (x,y,z,w,v) = s % x % y % z % w % v++-- | Formats six values into a string without finalizing.+(%%%%%%) :: (Show a, Show b, Show c, Show d, Show e, Show f)+         => String -> (a,b,c,d,e,f) -> String+s %%%%%% (x,y,z,w,v,u) = s % x % y % z % w % v % u++-- | Formats two values into a string and finalizes it:+--   removing duplicate percent signs & replacing remaining format sequences+--   with interrogation marks.+--+-- > > "%s %s!" -%% ("Hello","World")+-- > "Hello World!"+--+-- > > "load avg: %.2f %.2f %.2f" -%% (0.666,0.333)+-- > "load avg: %0.67 %0.33 ?"+--+-- In general:+--+-- > s -%% (x,y) == s % x -% y+--+-- Please use '%%' if you intend to further format values.+(-%%) :: (Show a, Show b) => String -> (a,b) -> String+s -%% t = s %% t /% '?'++-- | Formats three values into a string and finalizes it.+--+-- > > "load avg: %.2f %.2f %.2f" -%%% (0.666,0.333,0.1)+-- > "load avg: %0.67 %0.33 %0.10"+(-%%%) :: (Show a, Show b, Show c) => String -> (a,b,c) -> String+s -%%% t = s %%% t /% '?'++-- | Formats four values into a string and finalizes it.+(-%%%%) :: (Show a, Show b, Show c, Show d) => String -> (a,b,c,d) -> String+s -%%%% t = s %%%% t /% '?'++-- | Formats five values into a string and finalizes it.+(-%%%%%) :: (Show a, Show b, Show c, Show d, Show e)+        => String -> (a,b,c,d,e) -> String+s -%%%%% t = s %%%%% t /% '?'++-- | Formats six values into a stirng and finalizes it.+(-%%%%%%) :: (Show a, Show b, Show c, Show d, Show e, Show f)+         => String -> (a,b,c,d,e,f) -> String+s -%%%%%% t = s %%%%%% t /% '?'++-- | Just an alias to '%' for use whenever "Data.Ratio" is in scope.+--+-- > import Data.Ratio+-- > import Text.PercentFormat hiding ((%))+-- > "..." +% 1 -% 2+(+%) :: Show a => String -> a -> String+(+%) = (%)
+ src/Text/PercentFormat/Quotient.hs view
@@ -0,0 +1,202 @@+-- |+-- Module      : Text.PercentFormat.Quotient+-- Copyright   : (c) 2018 Rudy Matela+-- License     : 3-Clause BSD  (see the file LICENSE)+-- Maintainer  : Rudy Matela <rudy@matela.com.br>+--+-- The 'Quotient' datatype.  Similar to 'Rational' but allows @Infinity@ and+-- @NaN@.+module Text.PercentFormat.Quotient+  ( Quotient+  , (%)+  , infinity+  , nan+  , isInfinite+  , isNaN+  , readQ+  , maybeReadQ+  , digits+  , fracDigits+  )+where++import Prelude hiding (isInfinite, isNaN)+import Data.Char (isDigit)+import Data.Maybe (fromMaybe)+import Data.List (findIndex)+import qualified Data.Ratio as R+import Text.PercentFormat.Utils++-- | Our own Ratio type that allows Infinity and NaN+data Quotient = Integer :% Integer+infixl 7 :%++-- | 'Eq' instance for 'Quotient'.  Follows the identity property except for+--   NaN which is different from itself (this is consistent with 'Float' &+--   'Double' behaviour).+instance Eq Quotient where+  (0 :% 0) == _  =  False+  _ == (0 :% 0)  =  False+  (x :% y) == (x' :% y')  =  (x * y') == (x' * y)++-- | 'Ord' instance for 'Quotient'.  Follows the regular order properties+--   except for NaN.  When NaN is present in any of the operands of 'compare',+--   'GT' is returned (consistent with 'Float' & 'Double').+instance Ord Quotient where+  (0 :% 0) `compare` _  =  GT+  _ `compare` (0 :% 0)  =  GT+  (x :% y) `compare` (x' :% y') = (x * y') `compare` (x' * y)++instance Show Quotient where+  showsPrec d (0 :% 0) = showString "NaN"+  showsPrec d (x :% 0) | x < 0     = showParen (d > 6) $ showString "-Infinity"+                       | otherwise =                     showString  "Infinity"+  showsPrec d (x :% y) = showParen (d > 7)+                       $ showsPrec 7 x . showString " % " . showsPrec 7 y++-- | Smart-constructor for Quotients+(%) :: Integer -> Integer -> Quotient+0 % 0  =  0 :% 0         -- NaN+x % 0  =  signum x :% 0  -- (+/-) Infinity+x % y  =  (x * signum y `quot` d) :% (abs y `quot` d)+  where+  d = gcd x y+infixl 7 %++-- | Infinity.+infinity :: Quotient+infinity = 1 % 0++-- | Not a number @(0 / 0)@.+nan :: Quotient+nan = 0 % 0++-- | Returns whether a given quotient is an infinity (+/-).+isInfinite :: Quotient -> Bool+isInfinite q = q == infinity || q == (-infinity)++-- | Returns if the quotient is not a number.+isNaN :: Quotient -> Bool+isNaN q = q /= q+++instance Num Quotient where+  negate (x :% y)  =  negate x % y+  (x :% y) + (x' :% y')  =  (x * y'  +  x' * y) % (y * y')+  (x :% y) * (x' :% y')  =  (x * x') % (y * y')+  abs (x :% y)  =  abs x % abs y+  signum (x :% y)  =  signum x * signum y  %  1+  fromInteger  =  (% 1)++instance Fractional Quotient where+  recip (x :% y) = y % x+  fromRational q = R.numerator q % R.denominator q++instance Real Quotient where+  toRational (x :% y) = x R.% y++instance RealFrac Quotient where+  properFraction (x :% y) = (fromInteger q, r % y)+    where (q,r) = quotRem x y++-- TODO: change this ugly ad-hoc implementation into something that uses+--       readsPrec and related functions+maybeReadQ :: String -> Maybe Quotient+maybeReadQ "Infinity" = Just infinity+maybeReadQ "NaN"      = Just nan+maybeReadQ "inf"      = Just infinity  -- for Hugs+maybeReadQ "nan"      = Just nan       -- for Hugs+maybeReadQ ('-':s)    = negate <$> maybeReadQ s+  where+  f <$> Nothing   =  Nothing+  f <$> (Just x)  =  Just (f x)+maybeReadQ ('(':s)    = case span (/= ')') s of+                        (s',')':s'') -> maybeReadQ (s' ++ s'') -- ugly!+                        _ -> Nothing+maybeReadQ (d:s) | not (isDigit d) = Nothing+maybeReadQ etc = Just $+  case span isDigit etc of+  ("",_)      -> error "readQ: the impossible happened"+  (i,'.':etc) -> case span isDigit etc of+                 (j,'e':'-':e:tc) | isDigit e ->+                   read (i++j) % 10 ^ (length j + read (e:takeWhile isDigit tc))+                 (j,'e':e:tc) | isDigit e ->+                   read (i++j) * 10 ^ (read (e:takeWhile isDigit tc)) % 10 ^ length j+                 (j,etc) -> read (i++j) % 10 ^ length j+  (i,'%':e:tc) | isDigit e -> case span isDigit (e:tc) of+                              (j,etc) -> read i % read j+  (i,' ':'%':' ':e:tc) | isDigit e -> case span isDigit (e:tc) of+                                      (j,etc) -> read i % read j+  (i,etc)     -> read i % 1++readQ :: String -> Quotient+readQ = fromMaybe (error "No number to read") . maybeReadQ++-- | Given a quotient (rational number),+--   returns a tuple with+--   its integer part,+--   its fractional digits and+--   the period size (last fractional digits).+--   The signal is ignored.+--+-- > > digits 10 (1234567 / 100)+-- > Right ([1,2,3,4,5],[6,7],[])+-- > > digits 10 (1/3)+-- > Right ([0],[3],1)+-- > > digits 10 (1/6)+-- > Right ([0],[1,6],1)+-- > > digits 10 (1/7)+-- > Right ([0],[1,4,2,8,5,7],6)+-- > > digits 10 (1/11)+-- > Right ([0],[0,9],2)+-- > digits 10 (1/12)+-- > Right ([0],[0,8,3],1)+-- > > digits 10 (1/13)+-- > Right ([0],[0,7,6,9,2,3],6)+-- > > digits 10 123+-- > Right ([1,2,3],[],[])+-- > > digits 10 (-4/3)+-- > Right ([1],[],[3])+-- > > digits 10 (-1/3)+-- > Right ([0],[],[3])+digits :: Int -> Quotient -> Either String ([Int],[Int],[Int])+digits b (0 :% 0) = Left "NaN"+digits b (n :% 0) = Left "Infinity"+digits b q = Right (ids,fds,pds)+  where+  (i,q') = properFraction q+  (fds,pds) = fracDigits b q'+  ids = case integerToDigits b i of+        [] -> [0]+        ds -> ds++-- | Givent a base, returns the fractional digits of a Quotient (including a+--   period if present).+--+-- > > fracDigits 10 (123 / 100)+-- > ([2,3],[])+-- > > fracDigits 10 (12345 / 100)+-- > ([4,5],[])+-- > > fracDigits 10 (12345 / 10)+-- > ([5],[])+-- > > fracDigits 10 (100 / 10)+-- > ([],[])+-- > > fracDigits 10 (1 / 3)+-- > ([],[3])+-- > > fracDigits 10 (1 / 7)+-- > ([],[1,4,2,8,5,7])+fracDigits :: Int -> Quotient -> ([Int],[Int])+fracDigits b q | q < 0  = fracDigits b (abs q)+fracDigits b q | q >= 1 = fracDigits b (snd $ properFraction q)+fracDigits b q = let (fds,psz) = fun [] q+                     fsz = length fds - psz+                 in splitAt fsz fds+  where+  fun :: [(Integer,Integer)] -> Quotient -> ([Int],Int)+  fun hist (0 :% _) = ([],0)+  fun hist (x :% y) = case findIndex (==(x,y)) hist of+                      Nothing -> (fromInteger q:fds,psz)+                      Just i -> ([],i+1)+    where+    (q,r) = (x * toInteger b) `quotRem` y+    (fds,psz) = fun ((x,y):hist) (r % y)
+ src/Text/PercentFormat/Spec.hs view
@@ -0,0 +1,88 @@+-- |+-- Module      : Text.PercentFormat+-- Copyright   : (c) 2016-2018 Rudy Matela+-- License     : 3-Clause BSD  (see the file LICENSE)+-- Maintainer  : Rudy Matela <rudy@matela.com.br>+--+-- This file is part of PercentFormat a library for printf-style string+-- formatting.+--+-- This module provides the Spec type which represents a @%...@ specification+-- format.+module Text.PercentFormat.Spec where++import Data.Char (isDigit)++data Spec = Spec+  { ty        :: SpecType+  , width     :: Int+  , leftAlign :: Bool+  , padWith   :: Char+  , base      :: Int       -- ^ only for Number types+  , precision :: Maybe Int -- ^ only for Number types, Nothing for infinite+  , minPrecision :: Int    -- ^ minimum precision to show+  , positivePrefix :: String+  , capitalizeDigits :: Bool -- ^ whether to capitalize (hex) digits+  }+  deriving (Eq, Show)++data SpecType = NumberSpec+              | ReprSpec+              | StringSpec+              | CharSpec+              | Percent+  deriving (Eq, Show)++spec :: Spec+spec = Spec+  { ty        = error "undefined Spec ty"+  , width     = 0+  , leftAlign = False+  , padWith   = ' '+  , base      = 10+  , precision = Nothing+  , minPrecision = 0+  , positivePrefix = ""+  , capitalizeDigits = False+  }++parseSpec :: String -> (Spec,String)+parseSpec ('%':cs) = (spec {ty = Percent   }, cs)+parseSpec ('r':cs) = (spec {ty = ReprSpec  }, cs)+parseSpec ('s':cs) = (spec {ty = StringSpec}, cs)+parseSpec ('c':cs) = (spec {ty = CharSpec  }, cs)+parseSpec ('i':cs) = (spec {ty = NumberSpec, precision = Just 0}, cs)+parseSpec ('d':cs) = (spec {ty = NumberSpec}, cs)+parseSpec ('x':cs) = (spec {ty = NumberSpec, base = 16}, cs)+parseSpec ('X':cs) = (spec {ty = NumberSpec, base = 16, capitalizeDigits = True}, cs)+parseSpec ('o':cs) = (spec {ty = NumberSpec, base =  8}, cs)+parseSpec ('b':cs) = (spec {ty = NumberSpec, base =  2}, cs)+parseSpec ('f':cs) = (spec {ty = NumberSpec, minPrecision = 1}, cs)+parseSpec ('q':cs) = error $ "`q' format will be implemented in a future version"+parseSpec ('e':cs) = error $ "`e' format will be implemented in a future version"+parseSpec ('E':cs) = error $ "`E' format will be implemented in a future version"+parseSpec ('0':cs) = (s {padWith = '0'}, cs') where (s,cs') = parseSpec cs+parseSpec ( n :cs) | isDigit n = let (w,cs') = span isDigit (n:cs)+                                     (s,cs'') = parseSpec cs'+                                 in (s {width = read w}, cs'')+parseSpec ('.':'*':cs) = let (s,cs') = parseSpec cs+                         in (s {precision = Nothing}, cs')+parseSpec ('.':cs)             = let (w,cs')  = span isDigit cs+                                     (s,cs'') = parseSpec cs'+                                 in (s {precision = Just (read ('0':w))}, cs'')+parseSpec ('-':cs) = (s {leftAlign = True}, cs')     where (s,cs') = parseSpec cs+parseSpec (' ':cs) = (s {positivePrefix = " "}, cs') where (s,cs') = parseSpec cs+parseSpec ('+':cs) = (s {positivePrefix = "+"}, cs') where (s,cs') = parseSpec cs+parseSpec (c:_)    = error $ "unknown format string `" ++ (c:"'")+-- NOTE: for some reason:+-- > reads "4a" :: [(Int,String)]+-- [(4,"a")]+-- > reads "4." :: [(Int,String)]+-- [(4,".")]+-- > reads "4.0" :: [(Int,String)]+-- []+-- > reads "4.1" :: [(Int,String)]+-- []+-- > reads "4..1" :: [(Int,String)]+-- [(4,"..1")]+-- that's why I am using takeWhile above.
+ src/Text/PercentFormat/Utils.hs view
@@ -0,0 +1,105 @@+-- |+-- Module      : Text.PercentFormat+-- Copyright   : (c) 2016-2018 Rudy Matela+-- License     : 3-Clause BSD  (see the file LICENSE)+-- Maintainer  : Rudy Matela <rudy@matela.com.br>+--+-- This file is part of PercentFormat a library for printf-style string+-- formatting.+--+-- This module provides miscellaneous utility functions.+module Text.PercentFormat.Utils+  ( maybeRead+  , align+  , rightAlign+  , leftAlign+  , showWithBase+  , applyWhen+  , intsToDigits+  , theLast+  , loop+  , none+  , integerToDigits+  )+where++-- TODO: document this module more thoroughly++import Data.Maybe (listToMaybe)+import Data.List (unfoldr)+import Data.Char (intToDigit)++-- | Reads a value encoded as a string,+--   return 'Just' the value or 'Nothing' on error.+maybeRead :: Read a => String -> Maybe a+-- TODO: Use readsPrec to implement this.+maybeRead = listToMaybe . map fst . reads++align :: Bool -> Char -> Int -> String -> String+align left = if left+               then leftAlign+               else rightAlign++-- | @rightAlign c w s@ aligns 'String' @s@ to the right+--   in a field of width @w@ using 'Char' @c@ as padding.+--+-- > right ' ' 5 "123"+-- "  123"+rightAlign :: Char -> Int -> String -> String+rightAlign c width s | width <= len = s+                     | otherwise    = replicate (width - len) c ++ s+  where+  len = length s++-- | @left c w s@ aligns 'String' @s@ to the left+--   in a field of width @w@ using 'Char' @c@ as padding.+--+-- > left ' ' 5 "123"+-- "123  "+leftAlign :: Char -> Int -> String -> String+leftAlign c width s | width <= len = s+                    | otherwise    = s ++ replicate (width - len) c+  where+  len = length s++-- | @showWithBase b n@ returns a string representation of @n@ in base @b@.+--+-- > showWithBase 2 10+-- "1010"+-- > showWithBase 16 49406+-- "c0f3"+-- > showWithBase 10 (-1234)+-- "-1234"+showWithBase :: Integral a => Int -> a -> String+showWithBase b 0 = "0"+showWithBase b n | n < 0     = '-':showWithBase b (abs n)+                 | otherwise = map intToDigit $ integerToDigits b n++-- | Given an integer, returns a list of digits.  Signal is ignored.+integerToDigits :: Integral a => Int -> a -> [Int]+integerToDigits b =+    map fromIntegral+  . reverse+  . unfoldr (\n -> listToMaybe [swap $ n `divMod` fromIntegral b | n /= 0])+  . abs+  where+  swap (x,y) = (y,x)  -- not available on Hugs+++applyWhen :: Bool -> (a -> a) -> a -> a+applyWhen True  f x = f x+applyWhen False f x = x++intsToDigits :: [Int] -> String+intsToDigits = map intToDigit++theLast :: Int -> [a] -> [a]+theLast n xs = drop (length xs - n) xs++-- | Like cycle, but return an empty list when the source list is empty.+loop :: [a] -> [a]+loop [] = []+loop xs = cycle xs++none :: (a -> Bool) -> [a] -> Bool+none p = not . or . map p
+ stack.yaml view
@@ -0,0 +1,11 @@+# stack file for PercentFormat+resolver: lts-11.11++packages:+- .++extra-deps: []++flags: {}++extra-package-dbs: []
+ tests/Test.hs view
@@ -0,0 +1,21 @@+-- |+-- Module      : Test+-- Copyright   : (c) 2018 Rudy Matela+-- License     : 3-Clause BSD  (see the file LICENSE)+-- Maintainer  : Rudy Matela <rudy@matela.com.br>+--+-- This module is part of PercentFormat.+--+-- Some helper functios to test PercentFormat itself.+module Test where++import System.Environment (getArgs)+import System.Exit (exitFailure)+import Data.List (elemIndices)++reportTests :: [Bool] -> IO ()+reportTests tests =+  case elemIndices False tests of+    [] -> putStrLn "+++ Tests passed!"+    is -> do putStrLn ("*** Failed tests:" ++ show is)+             exitFailure
+ tests/diff/examples-+3i.out view
@@ -0,0 +1,63 @@+"%+3i" -% ""           == "!!!"+"%+3i" -% "a"          == "!!!"+"%+3i" -% "aa"         == "!!!"+"%+3i" -% " "          == "!!!"+"%+3i" -% "aaa"        == "!!!"+"%+3i" -% "a "         == "!!!"+"%+3i" -% " a"         == "!!!"+"%+3i" -% "b"          == "!!!"+"%+3i" -% "aaaa"       == "!!!"+"%+3i" -% "aa "        == "!!!"+"%+3i" -% "a a"        == "!!!"+"%+3i" -% "ab"         == "!!!"+"%+3i" -% 0            == " +0"+"%+3i" -% 1            == " +1"+"%+3i" -% (-1)         == " -1"+"%+3i" -% 2            == " +2"+"%+3i" -% (-2)         == " -2"+"%+3i" -% 3            == " +3"+"%+3i" -% (-3)         == " -3"+"%+3i" -% 4            == " +4"+"%+3i" -% (-4)         == " -4"+"%+3i" -% 5            == " +5"+"%+3i" -% (-5)         == " -5"+"%+3i" -% 6            == " +6"+"%+3i" -% 0.0          == " +0"+"%+3i" -% 1.0          == " +1"+"%+3i" -% 0.5          == " +0"+"%+3i" -% (-1.0)       == " -1"+"%+3i" -% 1.5          == " +2"+"%+3i" -% 0.25         == " +0"+"%+3i" -% Infinity     == "+Infinity"+"%+3i" -% 2.0          == " +2"+"%+3i" -% (-0.5)       == " -0"+"%+3i" -% 1.25         == " +1"+"%+3i" -% 0.75         == " +1"+"%+3i" -% (-Infinity)  == "-Infinity"+"%+3i" -% (0 % 1)      == " +0"+"%+3i" -% (1 % 1)      == " +1"+"%+3i" -% ((-1) % 1)   == " -1"+"%+3i" -% (1 % 2)      == " +0"+"%+3i" -% (2 % 1)      == " +2"+"%+3i" -% ((-1) % 2)   == " -0"+"%+3i" -% ((-2) % 1)   == " -2"+"%+3i" -% (1 % 3)      == " +0"+"%+3i" -% (3 % 1)      == " +3"+"%+3i" -% ((-1) % 3)   == " -0"+"%+3i" -% ((-3) % 1)   == " -3"+"%+3i" -% (1 % 4)      == " +0"+"%+3i" -% 'a'          == "!!!"+"%+3i" -% ' '          == "!!!"+"%+3i" -% 'b'          == "!!!"+"%+3i" -% 'A'          == "!!!"+"%+3i" -% 'c'          == "!!!"+"%+3i" -% '\n'         == "!!!"+"%+3i" -% 'd'          == "!!!"+"%+3i" -% '0'          == "!!!"+"%+3i" -% 'e'          == "!!!"+"%+3i" -% 'B'          == "!!!"+"%+3i" -% 'f'          == "!!!"+"%+3i" -% '!'          == "!!!"+"%+3i" -% False        == "!!!"+"%+3i" -% True         == "!!!"+
+ tests/diff/examples-+5f.out view
@@ -0,0 +1,63 @@+"%+5f" -% ""           == "!!!!!"+"%+5f" -% "a"          == "!!!!!"+"%+5f" -% "aa"         == "!!!!!"+"%+5f" -% " "          == "!!!!!"+"%+5f" -% "aaa"        == "!!!!!"+"%+5f" -% "a "         == "!!!!!"+"%+5f" -% " a"         == "!!!!!"+"%+5f" -% "b"          == "!!!!!"+"%+5f" -% "aaaa"       == "!!!!!"+"%+5f" -% "aa "        == "!!!!!"+"%+5f" -% "a a"        == "!!!!!"+"%+5f" -% "ab"         == "!!!!!"+"%+5f" -% 0            == " +0.0"+"%+5f" -% 1            == " +1.0"+"%+5f" -% (-1)         == " -1.0"+"%+5f" -% 2            == " +2.0"+"%+5f" -% (-2)         == " -2.0"+"%+5f" -% 3            == " +3.0"+"%+5f" -% (-3)         == " -3.0"+"%+5f" -% 4            == " +4.0"+"%+5f" -% (-4)         == " -4.0"+"%+5f" -% 5            == " +5.0"+"%+5f" -% (-5)         == " -5.0"+"%+5f" -% 6            == " +6.0"+"%+5f" -% 0.0          == " +0.0"+"%+5f" -% 1.0          == " +1.0"+"%+5f" -% 0.5          == " +0.5"+"%+5f" -% (-1.0)       == " -1.0"+"%+5f" -% 1.5          == " +1.5"+"%+5f" -% 0.25         == "+0.25"+"%+5f" -% Infinity     == "+Infinity"+"%+5f" -% 2.0          == " +2.0"+"%+5f" -% (-0.5)       == " -0.5"+"%+5f" -% 1.25         == "+1.25"+"%+5f" -% 0.75         == "+0.75"+"%+5f" -% (-Infinity)  == "-Infinity"+"%+5f" -% (0 % 1)      == " +0.0"+"%+5f" -% (1 % 1)      == " +1.0"+"%+5f" -% ((-1) % 1)   == " -1.0"+"%+5f" -% (1 % 2)      == " +0.5"+"%+5f" -% (2 % 1)      == " +2.0"+"%+5f" -% ((-1) % 2)   == " -0.5"+"%+5f" -% ((-2) % 1)   == " -2.0"+"%+5f" -% (1 % 3)      == "   +0"+"%+5f" -% (3 % 1)      == " +3.0"+"%+5f" -% ((-1) % 3)   == "   -0"+"%+5f" -% ((-3) % 1)   == " -3.0"+"%+5f" -% (1 % 4)      == "+0.25"+"%+5f" -% 'a'          == "!!!!!"+"%+5f" -% ' '          == "!!!!!"+"%+5f" -% 'b'          == "!!!!!"+"%+5f" -% 'A'          == "!!!!!"+"%+5f" -% 'c'          == "!!!!!"+"%+5f" -% '\n'         == "!!!!!"+"%+5f" -% 'd'          == "!!!!!"+"%+5f" -% '0'          == "!!!!!"+"%+5f" -% 'e'          == "!!!!!"+"%+5f" -% 'B'          == "!!!!!"+"%+5f" -% 'f'          == "!!!!!"+"%+5f" -% '!'          == "!!!!!"+"%+5f" -% False        == "!!!!!"+"%+5f" -% True         == "!!!!!"+
+ tests/diff/examples--11p2f.out view
@@ -0,0 +1,63 @@+"%-11.2f" -% ""           == "!!!!!!!!!!!"+"%-11.2f" -% "a"          == "!!!!!!!!!!!"+"%-11.2f" -% "aa"         == "!!!!!!!!!!!"+"%-11.2f" -% " "          == "!!!!!!!!!!!"+"%-11.2f" -% "aaa"        == "!!!!!!!!!!!"+"%-11.2f" -% "a "         == "!!!!!!!!!!!"+"%-11.2f" -% " a"         == "!!!!!!!!!!!"+"%-11.2f" -% "b"          == "!!!!!!!!!!!"+"%-11.2f" -% "aaaa"       == "!!!!!!!!!!!"+"%-11.2f" -% "aa "        == "!!!!!!!!!!!"+"%-11.2f" -% "a a"        == "!!!!!!!!!!!"+"%-11.2f" -% "ab"         == "!!!!!!!!!!!"+"%-11.2f" -% 0            == "0.00       "+"%-11.2f" -% 1            == "1.00       "+"%-11.2f" -% (-1)         == "-1.00      "+"%-11.2f" -% 2            == "2.00       "+"%-11.2f" -% (-2)         == "-2.00      "+"%-11.2f" -% 3            == "3.00       "+"%-11.2f" -% (-3)         == "-3.00      "+"%-11.2f" -% 4            == "4.00       "+"%-11.2f" -% (-4)         == "-4.00      "+"%-11.2f" -% 5            == "5.00       "+"%-11.2f" -% (-5)         == "-5.00      "+"%-11.2f" -% 6            == "6.00       "+"%-11.2f" -% 0.0          == "0.00       "+"%-11.2f" -% 1.0          == "1.00       "+"%-11.2f" -% 0.5          == "0.50       "+"%-11.2f" -% (-1.0)       == "-1.00      "+"%-11.2f" -% 1.5          == "1.50       "+"%-11.2f" -% 0.25         == "0.25       "+"%-11.2f" -% Infinity     == "Infinity   "+"%-11.2f" -% 2.0          == "2.00       "+"%-11.2f" -% (-0.5)       == "-0.50      "+"%-11.2f" -% 1.25         == "1.25       "+"%-11.2f" -% 0.75         == "0.75       "+"%-11.2f" -% (-Infinity)  == "-Infinity  "+"%-11.2f" -% (0 % 1)      == "0.00       "+"%-11.2f" -% (1 % 1)      == "1.00       "+"%-11.2f" -% ((-1) % 1)   == "-1.00      "+"%-11.2f" -% (1 % 2)      == "0.50       "+"%-11.2f" -% (2 % 1)      == "2.00       "+"%-11.2f" -% ((-1) % 2)   == "-0.50      "+"%-11.2f" -% ((-2) % 1)   == "-2.00      "+"%-11.2f" -% (1 % 3)      == "0.33       "+"%-11.2f" -% (3 % 1)      == "3.00       "+"%-11.2f" -% ((-1) % 3)   == "-0.33      "+"%-11.2f" -% ((-3) % 1)   == "-3.00      "+"%-11.2f" -% (1 % 4)      == "0.25       "+"%-11.2f" -% 'a'          == "!!!!!!!!!!!"+"%-11.2f" -% ' '          == "!!!!!!!!!!!"+"%-11.2f" -% 'b'          == "!!!!!!!!!!!"+"%-11.2f" -% 'A'          == "!!!!!!!!!!!"+"%-11.2f" -% 'c'          == "!!!!!!!!!!!"+"%-11.2f" -% '\n'         == "!!!!!!!!!!!"+"%-11.2f" -% 'd'          == "!!!!!!!!!!!"+"%-11.2f" -% '0'          == "!!!!!!!!!!!"+"%-11.2f" -% 'e'          == "!!!!!!!!!!!"+"%-11.2f" -% 'B'          == "!!!!!!!!!!!"+"%-11.2f" -% 'f'          == "!!!!!!!!!!!"+"%-11.2f" -% '!'          == "!!!!!!!!!!!"+"%-11.2f" -% False        == "!!!!!!!!!!!"+"%-11.2f" -% True         == "!!!!!!!!!!!"+
+ tests/diff/examples--3i.out view
@@ -0,0 +1,63 @@+"%-3i" -% ""           == "!!!"+"%-3i" -% "a"          == "!!!"+"%-3i" -% "aa"         == "!!!"+"%-3i" -% " "          == "!!!"+"%-3i" -% "aaa"        == "!!!"+"%-3i" -% "a "         == "!!!"+"%-3i" -% " a"         == "!!!"+"%-3i" -% "b"          == "!!!"+"%-3i" -% "aaaa"       == "!!!"+"%-3i" -% "aa "        == "!!!"+"%-3i" -% "a a"        == "!!!"+"%-3i" -% "ab"         == "!!!"+"%-3i" -% 0            == "0  "+"%-3i" -% 1            == "1  "+"%-3i" -% (-1)         == "-1 "+"%-3i" -% 2            == "2  "+"%-3i" -% (-2)         == "-2 "+"%-3i" -% 3            == "3  "+"%-3i" -% (-3)         == "-3 "+"%-3i" -% 4            == "4  "+"%-3i" -% (-4)         == "-4 "+"%-3i" -% 5            == "5  "+"%-3i" -% (-5)         == "-5 "+"%-3i" -% 6            == "6  "+"%-3i" -% 0.0          == "0  "+"%-3i" -% 1.0          == "1  "+"%-3i" -% 0.5          == "0  "+"%-3i" -% (-1.0)       == "-1 "+"%-3i" -% 1.5          == "2  "+"%-3i" -% 0.25         == "0  "+"%-3i" -% Infinity     == "Infinity"+"%-3i" -% 2.0          == "2  "+"%-3i" -% (-0.5)       == "-0 "+"%-3i" -% 1.25         == "1  "+"%-3i" -% 0.75         == "1  "+"%-3i" -% (-Infinity)  == "-Infinity"+"%-3i" -% (0 % 1)      == "0  "+"%-3i" -% (1 % 1)      == "1  "+"%-3i" -% ((-1) % 1)   == "-1 "+"%-3i" -% (1 % 2)      == "0  "+"%-3i" -% (2 % 1)      == "2  "+"%-3i" -% ((-1) % 2)   == "-0 "+"%-3i" -% ((-2) % 1)   == "-2 "+"%-3i" -% (1 % 3)      == "0  "+"%-3i" -% (3 % 1)      == "3  "+"%-3i" -% ((-1) % 3)   == "-0 "+"%-3i" -% ((-3) % 1)   == "-3 "+"%-3i" -% (1 % 4)      == "0  "+"%-3i" -% 'a'          == "!!!"+"%-3i" -% ' '          == "!!!"+"%-3i" -% 'b'          == "!!!"+"%-3i" -% 'A'          == "!!!"+"%-3i" -% 'c'          == "!!!"+"%-3i" -% '\n'         == "!!!"+"%-3i" -% 'd'          == "!!!"+"%-3i" -% '0'          == "!!!"+"%-3i" -% 'e'          == "!!!"+"%-3i" -% 'B'          == "!!!"+"%-3i" -% 'f'          == "!!!"+"%-3i" -% '!'          == "!!!"+"%-3i" -% False        == "!!!"+"%-3i" -% True         == "!!!"+
+ tests/diff/examples--5f.out view
@@ -0,0 +1,63 @@+"%-5f" -% ""           == "!!!!!"+"%-5f" -% "a"          == "!!!!!"+"%-5f" -% "aa"         == "!!!!!"+"%-5f" -% " "          == "!!!!!"+"%-5f" -% "aaa"        == "!!!!!"+"%-5f" -% "a "         == "!!!!!"+"%-5f" -% " a"         == "!!!!!"+"%-5f" -% "b"          == "!!!!!"+"%-5f" -% "aaaa"       == "!!!!!"+"%-5f" -% "aa "        == "!!!!!"+"%-5f" -% "a a"        == "!!!!!"+"%-5f" -% "ab"         == "!!!!!"+"%-5f" -% 0            == "0.0  "+"%-5f" -% 1            == "1.0  "+"%-5f" -% (-1)         == "-1.0 "+"%-5f" -% 2            == "2.0  "+"%-5f" -% (-2)         == "-2.0 "+"%-5f" -% 3            == "3.0  "+"%-5f" -% (-3)         == "-3.0 "+"%-5f" -% 4            == "4.0  "+"%-5f" -% (-4)         == "-4.0 "+"%-5f" -% 5            == "5.0  "+"%-5f" -% (-5)         == "-5.0 "+"%-5f" -% 6            == "6.0  "+"%-5f" -% 0.0          == "0.0  "+"%-5f" -% 1.0          == "1.0  "+"%-5f" -% 0.5          == "0.5  "+"%-5f" -% (-1.0)       == "-1.0 "+"%-5f" -% 1.5          == "1.5  "+"%-5f" -% 0.25         == "0.25 "+"%-5f" -% Infinity     == "Infinity"+"%-5f" -% 2.0          == "2.0  "+"%-5f" -% (-0.5)       == "-0.5 "+"%-5f" -% 1.25         == "1.25 "+"%-5f" -% 0.75         == "0.75 "+"%-5f" -% (-Infinity)  == "-Infinity"+"%-5f" -% (0 % 1)      == "0.0  "+"%-5f" -% (1 % 1)      == "1.0  "+"%-5f" -% ((-1) % 1)   == "-1.0 "+"%-5f" -% (1 % 2)      == "0.5  "+"%-5f" -% (2 % 1)      == "2.0  "+"%-5f" -% ((-1) % 2)   == "-0.5 "+"%-5f" -% ((-2) % 1)   == "-2.0 "+"%-5f" -% (1 % 3)      == "0    "+"%-5f" -% (3 % 1)      == "3.0  "+"%-5f" -% ((-1) % 3)   == "-0   "+"%-5f" -% ((-3) % 1)   == "-3.0 "+"%-5f" -% (1 % 4)      == "0.25 "+"%-5f" -% 'a'          == "!!!!!"+"%-5f" -% ' '          == "!!!!!"+"%-5f" -% 'b'          == "!!!!!"+"%-5f" -% 'A'          == "!!!!!"+"%-5f" -% 'c'          == "!!!!!"+"%-5f" -% '\n'         == "!!!!!"+"%-5f" -% 'd'          == "!!!!!"+"%-5f" -% '0'          == "!!!!!"+"%-5f" -% 'e'          == "!!!!!"+"%-5f" -% 'B'          == "!!!!!"+"%-5f" -% 'f'          == "!!!!!"+"%-5f" -% '!'          == "!!!!!"+"%-5f" -% False        == "!!!!!"+"%-5f" -% True         == "!!!!!"+
+ tests/diff/examples--6r.out view
@@ -0,0 +1,63 @@+"%-6r" -% ""           == "\"\"    "+"%-6r" -% "a"          == "\"a\"   "+"%-6r" -% "aa"         == "\"aa\"  "+"%-6r" -% " "          == "\" \"   "+"%-6r" -% "aaa"        == "\"aaa\" "+"%-6r" -% "a "         == "\"a \"  "+"%-6r" -% " a"         == "\" a\"  "+"%-6r" -% "b"          == "\"b\"   "+"%-6r" -% "aaaa"       == "\"aaaa\""+"%-6r" -% "aa "        == "\"aa \" "+"%-6r" -% "a a"        == "\"a a\" "+"%-6r" -% "ab"         == "\"ab\"  "+"%-6r" -% 0            == "0     "+"%-6r" -% 1            == "1     "+"%-6r" -% (-1)         == "-1    "+"%-6r" -% 2            == "2     "+"%-6r" -% (-2)         == "-2    "+"%-6r" -% 3            == "3     "+"%-6r" -% (-3)         == "-3    "+"%-6r" -% 4            == "4     "+"%-6r" -% (-4)         == "-4    "+"%-6r" -% 5            == "5     "+"%-6r" -% (-5)         == "-5    "+"%-6r" -% 6            == "6     "+"%-6r" -% 0.0          == "0.0   "+"%-6r" -% 1.0          == "1.0   "+"%-6r" -% 0.5          == "0.5   "+"%-6r" -% (-1.0)       == "-1.0  "+"%-6r" -% 1.5          == "1.5   "+"%-6r" -% 0.25         == "0.25  "+"%-6r" -% Infinity     == "Infinity"+"%-6r" -% 2.0          == "2.0   "+"%-6r" -% (-0.5)       == "-0.5  "+"%-6r" -% 1.25         == "1.25  "+"%-6r" -% 0.75         == "0.75  "+"%-6r" -% (-Infinity)  == "-Infinity"+"%-6r" -% (0 % 1)      == "0 % 1 "+"%-6r" -% (1 % 1)      == "1 % 1 "+"%-6r" -% ((-1) % 1)   == "(-1) % 1"+"%-6r" -% (1 % 2)      == "1 % 2 "+"%-6r" -% (2 % 1)      == "2 % 1 "+"%-6r" -% ((-1) % 2)   == "(-1) % 2"+"%-6r" -% ((-2) % 1)   == "(-2) % 1"+"%-6r" -% (1 % 3)      == "1 % 3 "+"%-6r" -% (3 % 1)      == "3 % 1 "+"%-6r" -% ((-1) % 3)   == "(-1) % 3"+"%-6r" -% ((-3) % 1)   == "(-3) % 1"+"%-6r" -% (1 % 4)      == "1 % 4 "+"%-6r" -% 'a'          == "'a'   "+"%-6r" -% ' '          == "' '   "+"%-6r" -% 'b'          == "'b'   "+"%-6r" -% 'A'          == "'A'   "+"%-6r" -% 'c'          == "'c'   "+"%-6r" -% '\n'         == "'\\n'  "+"%-6r" -% 'd'          == "'d'   "+"%-6r" -% '0'          == "'0'   "+"%-6r" -% 'e'          == "'e'   "+"%-6r" -% 'B'          == "'B'   "+"%-6r" -% 'f'          == "'f'   "+"%-6r" -% '!'          == "'!'   "+"%-6r" -% False        == "False "+"%-6r" -% True         == "True  "+
+ tests/diff/examples--6s.out view
@@ -0,0 +1,63 @@+"%-6s" -% ""           == "      "+"%-6s" -% "a"          == "a     "+"%-6s" -% "aa"         == "aa    "+"%-6s" -% " "          == "      "+"%-6s" -% "aaa"        == "aaa   "+"%-6s" -% "a "         == "a     "+"%-6s" -% " a"         == " a    "+"%-6s" -% "b"          == "b     "+"%-6s" -% "aaaa"       == "aaaa  "+"%-6s" -% "aa "        == "aa    "+"%-6s" -% "a a"        == "a a   "+"%-6s" -% "ab"         == "ab    "+"%-6s" -% 0            == "0     "+"%-6s" -% 1            == "1     "+"%-6s" -% (-1)         == "-1    "+"%-6s" -% 2            == "2     "+"%-6s" -% (-2)         == "-2    "+"%-6s" -% 3            == "3     "+"%-6s" -% (-3)         == "-3    "+"%-6s" -% 4            == "4     "+"%-6s" -% (-4)         == "-4    "+"%-6s" -% 5            == "5     "+"%-6s" -% (-5)         == "-5    "+"%-6s" -% 6            == "6     "+"%-6s" -% 0.0          == "0.0   "+"%-6s" -% 1.0          == "1.0   "+"%-6s" -% 0.5          == "0.5   "+"%-6s" -% (-1.0)       == "-1.0  "+"%-6s" -% 1.5          == "1.5   "+"%-6s" -% 0.25         == "0.25  "+"%-6s" -% Infinity     == "Infinity"+"%-6s" -% 2.0          == "2.0   "+"%-6s" -% (-0.5)       == "-0.5  "+"%-6s" -% 1.25         == "1.25  "+"%-6s" -% 0.75         == "0.75  "+"%-6s" -% (-Infinity)  == "-Infinity"+"%-6s" -% (0 % 1)      == "0 % 1 "+"%-6s" -% (1 % 1)      == "1 % 1 "+"%-6s" -% ((-1) % 1)   == "(-1) % 1"+"%-6s" -% (1 % 2)      == "1 % 2 "+"%-6s" -% (2 % 1)      == "2 % 1 "+"%-6s" -% ((-1) % 2)   == "(-1) % 2"+"%-6s" -% ((-2) % 1)   == "(-2) % 1"+"%-6s" -% (1 % 3)      == "1 % 3 "+"%-6s" -% (3 % 1)      == "3 % 1 "+"%-6s" -% ((-1) % 3)   == "(-1) % 3"+"%-6s" -% ((-3) % 1)   == "(-3) % 1"+"%-6s" -% (1 % 4)      == "1 % 4 "+"%-6s" -% 'a'          == "'a'   "+"%-6s" -% ' '          == "' '   "+"%-6s" -% 'b'          == "'b'   "+"%-6s" -% 'A'          == "'A'   "+"%-6s" -% 'c'          == "'c'   "+"%-6s" -% '\n'         == "'\\n'  "+"%-6s" -% 'd'          == "'d'   "+"%-6s" -% '0'          == "'0'   "+"%-6s" -% 'e'          == "'e'   "+"%-6s" -% 'B'          == "'B'   "+"%-6s" -% 'f'          == "'f'   "+"%-6s" -% '!'          == "'!'   "+"%-6s" -% False        == "False "+"%-6s" -% True         == "True  "+
+ tests/diff/examples-03i.out view
@@ -0,0 +1,63 @@+"%03i" -% ""           == "!!!"+"%03i" -% "a"          == "!!!"+"%03i" -% "aa"         == "!!!"+"%03i" -% " "          == "!!!"+"%03i" -% "aaa"        == "!!!"+"%03i" -% "a "         == "!!!"+"%03i" -% " a"         == "!!!"+"%03i" -% "b"          == "!!!"+"%03i" -% "aaaa"       == "!!!"+"%03i" -% "aa "        == "!!!"+"%03i" -% "a a"        == "!!!"+"%03i" -% "ab"         == "!!!"+"%03i" -% 0            == "000"+"%03i" -% 1            == "001"+"%03i" -% (-1)         == "-01"+"%03i" -% 2            == "002"+"%03i" -% (-2)         == "-02"+"%03i" -% 3            == "003"+"%03i" -% (-3)         == "-03"+"%03i" -% 4            == "004"+"%03i" -% (-4)         == "-04"+"%03i" -% 5            == "005"+"%03i" -% (-5)         == "-05"+"%03i" -% 6            == "006"+"%03i" -% 0.0          == "000"+"%03i" -% 1.0          == "001"+"%03i" -% 0.5          == "000"+"%03i" -% (-1.0)       == "-01"+"%03i" -% 1.5          == "002"+"%03i" -% 0.25         == "000"+"%03i" -% Infinity     == "Infinity"+"%03i" -% 2.0          == "002"+"%03i" -% (-0.5)       == "-00"+"%03i" -% 1.25         == "001"+"%03i" -% 0.75         == "001"+"%03i" -% (-Infinity)  == "-Infinity"+"%03i" -% (0 % 1)      == "000"+"%03i" -% (1 % 1)      == "001"+"%03i" -% ((-1) % 1)   == "-01"+"%03i" -% (1 % 2)      == "000"+"%03i" -% (2 % 1)      == "002"+"%03i" -% ((-1) % 2)   == "-00"+"%03i" -% ((-2) % 1)   == "-02"+"%03i" -% (1 % 3)      == "000"+"%03i" -% (3 % 1)      == "003"+"%03i" -% ((-1) % 3)   == "-00"+"%03i" -% ((-3) % 1)   == "-03"+"%03i" -% (1 % 4)      == "000"+"%03i" -% 'a'          == "!!!"+"%03i" -% ' '          == "!!!"+"%03i" -% 'b'          == "!!!"+"%03i" -% 'A'          == "!!!"+"%03i" -% 'c'          == "!!!"+"%03i" -% '\n'         == "!!!"+"%03i" -% 'd'          == "!!!"+"%03i" -% '0'          == "!!!"+"%03i" -% 'e'          == "!!!"+"%03i" -% 'B'          == "!!!"+"%03i" -% 'f'          == "!!!"+"%03i" -% '!'          == "!!!"+"%03i" -% False        == "!!!"+"%03i" -% True         == "!!!"+
+ tests/diff/examples-11p2f.out view
@@ -0,0 +1,63 @@+"%11.2f" -% ""           == "!!!!!!!!!!!"+"%11.2f" -% "a"          == "!!!!!!!!!!!"+"%11.2f" -% "aa"         == "!!!!!!!!!!!"+"%11.2f" -% " "          == "!!!!!!!!!!!"+"%11.2f" -% "aaa"        == "!!!!!!!!!!!"+"%11.2f" -% "a "         == "!!!!!!!!!!!"+"%11.2f" -% " a"         == "!!!!!!!!!!!"+"%11.2f" -% "b"          == "!!!!!!!!!!!"+"%11.2f" -% "aaaa"       == "!!!!!!!!!!!"+"%11.2f" -% "aa "        == "!!!!!!!!!!!"+"%11.2f" -% "a a"        == "!!!!!!!!!!!"+"%11.2f" -% "ab"         == "!!!!!!!!!!!"+"%11.2f" -% 0            == "       0.00"+"%11.2f" -% 1            == "       1.00"+"%11.2f" -% (-1)         == "      -1.00"+"%11.2f" -% 2            == "       2.00"+"%11.2f" -% (-2)         == "      -2.00"+"%11.2f" -% 3            == "       3.00"+"%11.2f" -% (-3)         == "      -3.00"+"%11.2f" -% 4            == "       4.00"+"%11.2f" -% (-4)         == "      -4.00"+"%11.2f" -% 5            == "       5.00"+"%11.2f" -% (-5)         == "      -5.00"+"%11.2f" -% 6            == "       6.00"+"%11.2f" -% 0.0          == "       0.00"+"%11.2f" -% 1.0          == "       1.00"+"%11.2f" -% 0.5          == "       0.50"+"%11.2f" -% (-1.0)       == "      -1.00"+"%11.2f" -% 1.5          == "       1.50"+"%11.2f" -% 0.25         == "       0.25"+"%11.2f" -% Infinity     == "   Infinity"+"%11.2f" -% 2.0          == "       2.00"+"%11.2f" -% (-0.5)       == "      -0.50"+"%11.2f" -% 1.25         == "       1.25"+"%11.2f" -% 0.75         == "       0.75"+"%11.2f" -% (-Infinity)  == "  -Infinity"+"%11.2f" -% (0 % 1)      == "       0.00"+"%11.2f" -% (1 % 1)      == "       1.00"+"%11.2f" -% ((-1) % 1)   == "      -1.00"+"%11.2f" -% (1 % 2)      == "       0.50"+"%11.2f" -% (2 % 1)      == "       2.00"+"%11.2f" -% ((-1) % 2)   == "      -0.50"+"%11.2f" -% ((-2) % 1)   == "      -2.00"+"%11.2f" -% (1 % 3)      == "       0.33"+"%11.2f" -% (3 % 1)      == "       3.00"+"%11.2f" -% ((-1) % 3)   == "      -0.33"+"%11.2f" -% ((-3) % 1)   == "      -3.00"+"%11.2f" -% (1 % 4)      == "       0.25"+"%11.2f" -% 'a'          == "!!!!!!!!!!!"+"%11.2f" -% ' '          == "!!!!!!!!!!!"+"%11.2f" -% 'b'          == "!!!!!!!!!!!"+"%11.2f" -% 'A'          == "!!!!!!!!!!!"+"%11.2f" -% 'c'          == "!!!!!!!!!!!"+"%11.2f" -% '\n'         == "!!!!!!!!!!!"+"%11.2f" -% 'd'          == "!!!!!!!!!!!"+"%11.2f" -% '0'          == "!!!!!!!!!!!"+"%11.2f" -% 'e'          == "!!!!!!!!!!!"+"%11.2f" -% 'B'          == "!!!!!!!!!!!"+"%11.2f" -% 'f'          == "!!!!!!!!!!!"+"%11.2f" -% '!'          == "!!!!!!!!!!!"+"%11.2f" -% False        == "!!!!!!!!!!!"+"%11.2f" -% True         == "!!!!!!!!!!!"+
+ tests/diff/examples-2c.out view
@@ -0,0 +1,63 @@+"%2c" -% ""           == "!!"+"%2c" -% "a"          == "!!"+"%2c" -% "aa"         == "!!"+"%2c" -% " "          == "!!"+"%2c" -% "aaa"        == "!!"+"%2c" -% "a "         == "!!"+"%2c" -% " a"         == "!!"+"%2c" -% "b"          == "!!"+"%2c" -% "aaaa"       == "!!"+"%2c" -% "aa "        == "!!"+"%2c" -% "a a"        == "!!"+"%2c" -% "ab"         == "!!"+"%2c" -% 0            == "!!"+"%2c" -% 1            == "!!"+"%2c" -% (-1)         == "!!"+"%2c" -% 2            == "!!"+"%2c" -% (-2)         == "!!"+"%2c" -% 3            == "!!"+"%2c" -% (-3)         == "!!"+"%2c" -% 4            == "!!"+"%2c" -% (-4)         == "!!"+"%2c" -% 5            == "!!"+"%2c" -% (-5)         == "!!"+"%2c" -% 6            == "!!"+"%2c" -% 0.0          == "!!"+"%2c" -% 1.0          == "!!"+"%2c" -% 0.5          == "!!"+"%2c" -% (-1.0)       == "!!"+"%2c" -% 1.5          == "!!"+"%2c" -% 0.25         == "!!"+"%2c" -% Infinity     == "!!"+"%2c" -% 2.0          == "!!"+"%2c" -% (-0.5)       == "!!"+"%2c" -% 1.25         == "!!"+"%2c" -% 0.75         == "!!"+"%2c" -% (-Infinity)  == "!!"+"%2c" -% (0 % 1)      == "!!"+"%2c" -% (1 % 1)      == "!!"+"%2c" -% ((-1) % 1)   == "!!"+"%2c" -% (1 % 2)      == "!!"+"%2c" -% (2 % 1)      == "!!"+"%2c" -% ((-1) % 2)   == "!!"+"%2c" -% ((-2) % 1)   == "!!"+"%2c" -% (1 % 3)      == "!!"+"%2c" -% (3 % 1)      == "!!"+"%2c" -% ((-1) % 3)   == "!!"+"%2c" -% ((-3) % 1)   == "!!"+"%2c" -% (1 % 4)      == "!!"+"%2c" -% 'a'          == " a"+"%2c" -% ' '          == "  "+"%2c" -% 'b'          == " b"+"%2c" -% 'A'          == " A"+"%2c" -% 'c'          == " c"+"%2c" -% '\n'         == " \n"+"%2c" -% 'd'          == " d"+"%2c" -% '0'          == " 0"+"%2c" -% 'e'          == " e"+"%2c" -% 'B'          == " B"+"%2c" -% 'f'          == " f"+"%2c" -% '!'          == " !"+"%2c" -% False        == "!!"+"%2c" -% True         == "!!"+
+ tests/diff/examples-3i.out view
@@ -0,0 +1,63 @@+"%3i" -% ""           == "!!!"+"%3i" -% "a"          == "!!!"+"%3i" -% "aa"         == "!!!"+"%3i" -% " "          == "!!!"+"%3i" -% "aaa"        == "!!!"+"%3i" -% "a "         == "!!!"+"%3i" -% " a"         == "!!!"+"%3i" -% "b"          == "!!!"+"%3i" -% "aaaa"       == "!!!"+"%3i" -% "aa "        == "!!!"+"%3i" -% "a a"        == "!!!"+"%3i" -% "ab"         == "!!!"+"%3i" -% 0            == "  0"+"%3i" -% 1            == "  1"+"%3i" -% (-1)         == " -1"+"%3i" -% 2            == "  2"+"%3i" -% (-2)         == " -2"+"%3i" -% 3            == "  3"+"%3i" -% (-3)         == " -3"+"%3i" -% 4            == "  4"+"%3i" -% (-4)         == " -4"+"%3i" -% 5            == "  5"+"%3i" -% (-5)         == " -5"+"%3i" -% 6            == "  6"+"%3i" -% 0.0          == "  0"+"%3i" -% 1.0          == "  1"+"%3i" -% 0.5          == "  0"+"%3i" -% (-1.0)       == " -1"+"%3i" -% 1.5          == "  2"+"%3i" -% 0.25         == "  0"+"%3i" -% Infinity     == "Infinity"+"%3i" -% 2.0          == "  2"+"%3i" -% (-0.5)       == " -0"+"%3i" -% 1.25         == "  1"+"%3i" -% 0.75         == "  1"+"%3i" -% (-Infinity)  == "-Infinity"+"%3i" -% (0 % 1)      == "  0"+"%3i" -% (1 % 1)      == "  1"+"%3i" -% ((-1) % 1)   == " -1"+"%3i" -% (1 % 2)      == "  0"+"%3i" -% (2 % 1)      == "  2"+"%3i" -% ((-1) % 2)   == " -0"+"%3i" -% ((-2) % 1)   == " -2"+"%3i" -% (1 % 3)      == "  0"+"%3i" -% (3 % 1)      == "  3"+"%3i" -% ((-1) % 3)   == " -0"+"%3i" -% ((-3) % 1)   == " -3"+"%3i" -% (1 % 4)      == "  0"+"%3i" -% 'a'          == "!!!"+"%3i" -% ' '          == "!!!"+"%3i" -% 'b'          == "!!!"+"%3i" -% 'A'          == "!!!"+"%3i" -% 'c'          == "!!!"+"%3i" -% '\n'         == "!!!"+"%3i" -% 'd'          == "!!!"+"%3i" -% '0'          == "!!!"+"%3i" -% 'e'          == "!!!"+"%3i" -% 'B'          == "!!!"+"%3i" -% 'f'          == "!!!"+"%3i" -% '!'          == "!!!"+"%3i" -% False        == "!!!"+"%3i" -% True         == "!!!"+
+ tests/diff/examples-5f.out view
@@ -0,0 +1,63 @@+"%5f" -% ""           == "!!!!!"+"%5f" -% "a"          == "!!!!!"+"%5f" -% "aa"         == "!!!!!"+"%5f" -% " "          == "!!!!!"+"%5f" -% "aaa"        == "!!!!!"+"%5f" -% "a "         == "!!!!!"+"%5f" -% " a"         == "!!!!!"+"%5f" -% "b"          == "!!!!!"+"%5f" -% "aaaa"       == "!!!!!"+"%5f" -% "aa "        == "!!!!!"+"%5f" -% "a a"        == "!!!!!"+"%5f" -% "ab"         == "!!!!!"+"%5f" -% 0            == "  0.0"+"%5f" -% 1            == "  1.0"+"%5f" -% (-1)         == " -1.0"+"%5f" -% 2            == "  2.0"+"%5f" -% (-2)         == " -2.0"+"%5f" -% 3            == "  3.0"+"%5f" -% (-3)         == " -3.0"+"%5f" -% 4            == "  4.0"+"%5f" -% (-4)         == " -4.0"+"%5f" -% 5            == "  5.0"+"%5f" -% (-5)         == " -5.0"+"%5f" -% 6            == "  6.0"+"%5f" -% 0.0          == "  0.0"+"%5f" -% 1.0          == "  1.0"+"%5f" -% 0.5          == "  0.5"+"%5f" -% (-1.0)       == " -1.0"+"%5f" -% 1.5          == "  1.5"+"%5f" -% 0.25         == " 0.25"+"%5f" -% Infinity     == "Infinity"+"%5f" -% 2.0          == "  2.0"+"%5f" -% (-0.5)       == " -0.5"+"%5f" -% 1.25         == " 1.25"+"%5f" -% 0.75         == " 0.75"+"%5f" -% (-Infinity)  == "-Infinity"+"%5f" -% (0 % 1)      == "  0.0"+"%5f" -% (1 % 1)      == "  1.0"+"%5f" -% ((-1) % 1)   == " -1.0"+"%5f" -% (1 % 2)      == "  0.5"+"%5f" -% (2 % 1)      == "  2.0"+"%5f" -% ((-1) % 2)   == " -0.5"+"%5f" -% ((-2) % 1)   == " -2.0"+"%5f" -% (1 % 3)      == "    0"+"%5f" -% (3 % 1)      == "  3.0"+"%5f" -% ((-1) % 3)   == "   -0"+"%5f" -% ((-3) % 1)   == " -3.0"+"%5f" -% (1 % 4)      == " 0.25"+"%5f" -% 'a'          == "!!!!!"+"%5f" -% ' '          == "!!!!!"+"%5f" -% 'b'          == "!!!!!"+"%5f" -% 'A'          == "!!!!!"+"%5f" -% 'c'          == "!!!!!"+"%5f" -% '\n'         == "!!!!!"+"%5f" -% 'd'          == "!!!!!"+"%5f" -% '0'          == "!!!!!"+"%5f" -% 'e'          == "!!!!!"+"%5f" -% 'B'          == "!!!!!"+"%5f" -% 'f'          == "!!!!!"+"%5f" -% '!'          == "!!!!!"+"%5f" -% False        == "!!!!!"+"%5f" -% True         == "!!!!!"+
+ tests/diff/examples-6r.out view
@@ -0,0 +1,63 @@+"%6r" -% ""           == "    \"\""+"%6r" -% "a"          == "   \"a\""+"%6r" -% "aa"         == "  \"aa\""+"%6r" -% " "          == "   \" \""+"%6r" -% "aaa"        == " \"aaa\""+"%6r" -% "a "         == "  \"a \""+"%6r" -% " a"         == "  \" a\""+"%6r" -% "b"          == "   \"b\""+"%6r" -% "aaaa"       == "\"aaaa\""+"%6r" -% "aa "        == " \"aa \""+"%6r" -% "a a"        == " \"a a\""+"%6r" -% "ab"         == "  \"ab\""+"%6r" -% 0            == "     0"+"%6r" -% 1            == "     1"+"%6r" -% (-1)         == "    -1"+"%6r" -% 2            == "     2"+"%6r" -% (-2)         == "    -2"+"%6r" -% 3            == "     3"+"%6r" -% (-3)         == "    -3"+"%6r" -% 4            == "     4"+"%6r" -% (-4)         == "    -4"+"%6r" -% 5            == "     5"+"%6r" -% (-5)         == "    -5"+"%6r" -% 6            == "     6"+"%6r" -% 0.0          == "   0.0"+"%6r" -% 1.0          == "   1.0"+"%6r" -% 0.5          == "   0.5"+"%6r" -% (-1.0)       == "  -1.0"+"%6r" -% 1.5          == "   1.5"+"%6r" -% 0.25         == "  0.25"+"%6r" -% Infinity     == "Infinity"+"%6r" -% 2.0          == "   2.0"+"%6r" -% (-0.5)       == "  -0.5"+"%6r" -% 1.25         == "  1.25"+"%6r" -% 0.75         == "  0.75"+"%6r" -% (-Infinity)  == "-Infinity"+"%6r" -% (0 % 1)      == " 0 % 1"+"%6r" -% (1 % 1)      == " 1 % 1"+"%6r" -% ((-1) % 1)   == "(-1) % 1"+"%6r" -% (1 % 2)      == " 1 % 2"+"%6r" -% (2 % 1)      == " 2 % 1"+"%6r" -% ((-1) % 2)   == "(-1) % 2"+"%6r" -% ((-2) % 1)   == "(-2) % 1"+"%6r" -% (1 % 3)      == " 1 % 3"+"%6r" -% (3 % 1)      == " 3 % 1"+"%6r" -% ((-1) % 3)   == "(-1) % 3"+"%6r" -% ((-3) % 1)   == "(-3) % 1"+"%6r" -% (1 % 4)      == " 1 % 4"+"%6r" -% 'a'          == "   'a'"+"%6r" -% ' '          == "   ' '"+"%6r" -% 'b'          == "   'b'"+"%6r" -% 'A'          == "   'A'"+"%6r" -% 'c'          == "   'c'"+"%6r" -% '\n'         == "  '\\n'"+"%6r" -% 'd'          == "   'd'"+"%6r" -% '0'          == "   '0'"+"%6r" -% 'e'          == "   'e'"+"%6r" -% 'B'          == "   'B'"+"%6r" -% 'f'          == "   'f'"+"%6r" -% '!'          == "   '!'"+"%6r" -% False        == " False"+"%6r" -% True         == "  True"+
+ tests/diff/examples-6s.out view
@@ -0,0 +1,63 @@+"%6s" -% ""           == "      "+"%6s" -% "a"          == "     a"+"%6s" -% "aa"         == "    aa"+"%6s" -% " "          == "      "+"%6s" -% "aaa"        == "   aaa"+"%6s" -% "a "         == "    a "+"%6s" -% " a"         == "     a"+"%6s" -% "b"          == "     b"+"%6s" -% "aaaa"       == "  aaaa"+"%6s" -% "aa "        == "   aa "+"%6s" -% "a a"        == "   a a"+"%6s" -% "ab"         == "    ab"+"%6s" -% 0            == "     0"+"%6s" -% 1            == "     1"+"%6s" -% (-1)         == "    -1"+"%6s" -% 2            == "     2"+"%6s" -% (-2)         == "    -2"+"%6s" -% 3            == "     3"+"%6s" -% (-3)         == "    -3"+"%6s" -% 4            == "     4"+"%6s" -% (-4)         == "    -4"+"%6s" -% 5            == "     5"+"%6s" -% (-5)         == "    -5"+"%6s" -% 6            == "     6"+"%6s" -% 0.0          == "   0.0"+"%6s" -% 1.0          == "   1.0"+"%6s" -% 0.5          == "   0.5"+"%6s" -% (-1.0)       == "  -1.0"+"%6s" -% 1.5          == "   1.5"+"%6s" -% 0.25         == "  0.25"+"%6s" -% Infinity     == "Infinity"+"%6s" -% 2.0          == "   2.0"+"%6s" -% (-0.5)       == "  -0.5"+"%6s" -% 1.25         == "  1.25"+"%6s" -% 0.75         == "  0.75"+"%6s" -% (-Infinity)  == "-Infinity"+"%6s" -% (0 % 1)      == " 0 % 1"+"%6s" -% (1 % 1)      == " 1 % 1"+"%6s" -% ((-1) % 1)   == "(-1) % 1"+"%6s" -% (1 % 2)      == " 1 % 2"+"%6s" -% (2 % 1)      == " 2 % 1"+"%6s" -% ((-1) % 2)   == "(-1) % 2"+"%6s" -% ((-2) % 1)   == "(-2) % 1"+"%6s" -% (1 % 3)      == " 1 % 3"+"%6s" -% (3 % 1)      == " 3 % 1"+"%6s" -% ((-1) % 3)   == "(-1) % 3"+"%6s" -% ((-3) % 1)   == "(-3) % 1"+"%6s" -% (1 % 4)      == " 1 % 4"+"%6s" -% 'a'          == "   'a'"+"%6s" -% ' '          == "   ' '"+"%6s" -% 'b'          == "   'b'"+"%6s" -% 'A'          == "   'A'"+"%6s" -% 'c'          == "   'c'"+"%6s" -% '\n'         == "  '\\n'"+"%6s" -% 'd'          == "   'd'"+"%6s" -% '0'          == "   '0'"+"%6s" -% 'e'          == "   'e'"+"%6s" -% 'B'          == "   'B'"+"%6s" -% 'f'          == "   'f'"+"%6s" -% '!'          == "   '!'"+"%6s" -% False        == " False"+"%6s" -% True         == "  True"+
+ tests/diff/examples-X.out view
@@ -0,0 +1,63 @@+"%X" -% ""           == "!"+"%X" -% "a"          == "!"+"%X" -% "aa"         == "!"+"%X" -% " "          == "!"+"%X" -% "aaa"        == "!"+"%X" -% "a "         == "!"+"%X" -% " a"         == "!"+"%X" -% "b"          == "!"+"%X" -% "aaaa"       == "!"+"%X" -% "aa "        == "!"+"%X" -% "a a"        == "!"+"%X" -% "ab"         == "!"+"%X" -% 0            == "0"+"%X" -% 1            == "1"+"%X" -% (-1)         == "-1"+"%X" -% 2            == "2"+"%X" -% (-2)         == "-2"+"%X" -% 3            == "3"+"%X" -% (-3)         == "-3"+"%X" -% 4            == "4"+"%X" -% (-4)         == "-4"+"%X" -% 5            == "5"+"%X" -% (-5)         == "-5"+"%X" -% 6            == "6"+"%X" -% 0.0          == "0"+"%X" -% 1.0          == "1"+"%X" -% 0.5          == "0.8"+"%X" -% (-1.0)       == "-1"+"%X" -% 1.5          == "1.8"+"%X" -% 0.25         == "0.4"+"%X" -% Infinity     == "Infinity"+"%X" -% 2.0          == "2"+"%X" -% (-0.5)       == "-0.8"+"%X" -% 1.25         == "1.4"+"%X" -% 0.75         == "0.C"+"%X" -% (-Infinity)  == "-Infinity"+"%X" -% (0 % 1)      == "0"+"%X" -% (1 % 1)      == "1"+"%X" -% ((-1) % 1)   == "-1"+"%X" -% (1 % 2)      == "0.8"+"%X" -% (2 % 1)      == "2"+"%X" -% ((-1) % 2)   == "-0.8"+"%X" -% ((-2) % 1)   == "-2"+"%X" -% (1 % 3)      == "0"+"%X" -% (3 % 1)      == "3"+"%X" -% ((-1) % 3)   == "-0"+"%X" -% ((-3) % 1)   == "-3"+"%X" -% (1 % 4)      == "0.4"+"%X" -% 'a'          == "!"+"%X" -% ' '          == "!"+"%X" -% 'b'          == "!"+"%X" -% 'A'          == "!"+"%X" -% 'c'          == "!"+"%X" -% '\n'         == "!"+"%X" -% 'd'          == "!"+"%X" -% '0'          == "!"+"%X" -% 'e'          == "!"+"%X" -% 'B'          == "!"+"%X" -% 'f'          == "!"+"%X" -% '!'          == "!"+"%X" -% False        == "!"+"%X" -% True         == "!"+
+ tests/diff/examples-_3i.out view
@@ -0,0 +1,63 @@+"% 3i" -% ""           == "!!!"+"% 3i" -% "a"          == "!!!"+"% 3i" -% "aa"         == "!!!"+"% 3i" -% " "          == "!!!"+"% 3i" -% "aaa"        == "!!!"+"% 3i" -% "a "         == "!!!"+"% 3i" -% " a"         == "!!!"+"% 3i" -% "b"          == "!!!"+"% 3i" -% "aaaa"       == "!!!"+"% 3i" -% "aa "        == "!!!"+"% 3i" -% "a a"        == "!!!"+"% 3i" -% "ab"         == "!!!"+"% 3i" -% 0            == "  0"+"% 3i" -% 1            == "  1"+"% 3i" -% (-1)         == " -1"+"% 3i" -% 2            == "  2"+"% 3i" -% (-2)         == " -2"+"% 3i" -% 3            == "  3"+"% 3i" -% (-3)         == " -3"+"% 3i" -% 4            == "  4"+"% 3i" -% (-4)         == " -4"+"% 3i" -% 5            == "  5"+"% 3i" -% (-5)         == " -5"+"% 3i" -% 6            == "  6"+"% 3i" -% 0.0          == "  0"+"% 3i" -% 1.0          == "  1"+"% 3i" -% 0.5          == "  0"+"% 3i" -% (-1.0)       == " -1"+"% 3i" -% 1.5          == "  2"+"% 3i" -% 0.25         == "  0"+"% 3i" -% Infinity     == " Infinity"+"% 3i" -% 2.0          == "  2"+"% 3i" -% (-0.5)       == " -0"+"% 3i" -% 1.25         == "  1"+"% 3i" -% 0.75         == "  1"+"% 3i" -% (-Infinity)  == "-Infinity"+"% 3i" -% (0 % 1)      == "  0"+"% 3i" -% (1 % 1)      == "  1"+"% 3i" -% ((-1) % 1)   == " -1"+"% 3i" -% (1 % 2)      == "  0"+"% 3i" -% (2 % 1)      == "  2"+"% 3i" -% ((-1) % 2)   == " -0"+"% 3i" -% ((-2) % 1)   == " -2"+"% 3i" -% (1 % 3)      == "  0"+"% 3i" -% (3 % 1)      == "  3"+"% 3i" -% ((-1) % 3)   == " -0"+"% 3i" -% ((-3) % 1)   == " -3"+"% 3i" -% (1 % 4)      == "  0"+"% 3i" -% 'a'          == "!!!"+"% 3i" -% ' '          == "!!!"+"% 3i" -% 'b'          == "!!!"+"% 3i" -% 'A'          == "!!!"+"% 3i" -% 'c'          == "!!!"+"% 3i" -% '\n'         == "!!!"+"% 3i" -% 'd'          == "!!!"+"% 3i" -% '0'          == "!!!"+"% 3i" -% 'e'          == "!!!"+"% 3i" -% 'B'          == "!!!"+"% 3i" -% 'f'          == "!!!"+"% 3i" -% '!'          == "!!!"+"% 3i" -% False        == "!!!"+"% 3i" -% True         == "!!!"+
+ tests/diff/examples-abc.out view
@@ -0,0 +1,63 @@+"abc" -% ""           == "abc"+"abc" -% "a"          == "abc"+"abc" -% "aa"         == "abc"+"abc" -% " "          == "abc"+"abc" -% "aaa"        == "abc"+"abc" -% "a "         == "abc"+"abc" -% " a"         == "abc"+"abc" -% "b"          == "abc"+"abc" -% "aaaa"       == "abc"+"abc" -% "aa "        == "abc"+"abc" -% "a a"        == "abc"+"abc" -% "ab"         == "abc"+"abc" -% 0            == "abc"+"abc" -% 1            == "abc"+"abc" -% (-1)         == "abc"+"abc" -% 2            == "abc"+"abc" -% (-2)         == "abc"+"abc" -% 3            == "abc"+"abc" -% (-3)         == "abc"+"abc" -% 4            == "abc"+"abc" -% (-4)         == "abc"+"abc" -% 5            == "abc"+"abc" -% (-5)         == "abc"+"abc" -% 6            == "abc"+"abc" -% 0.0          == "abc"+"abc" -% 1.0          == "abc"+"abc" -% 0.5          == "abc"+"abc" -% (-1.0)       == "abc"+"abc" -% 1.5          == "abc"+"abc" -% 0.25         == "abc"+"abc" -% Infinity     == "abc"+"abc" -% 2.0          == "abc"+"abc" -% (-0.5)       == "abc"+"abc" -% 1.25         == "abc"+"abc" -% 0.75         == "abc"+"abc" -% (-Infinity)  == "abc"+"abc" -% (0 % 1)      == "abc"+"abc" -% (1 % 1)      == "abc"+"abc" -% ((-1) % 1)   == "abc"+"abc" -% (1 % 2)      == "abc"+"abc" -% (2 % 1)      == "abc"+"abc" -% ((-1) % 2)   == "abc"+"abc" -% ((-2) % 1)   == "abc"+"abc" -% (1 % 3)      == "abc"+"abc" -% (3 % 1)      == "abc"+"abc" -% ((-1) % 3)   == "abc"+"abc" -% ((-3) % 1)   == "abc"+"abc" -% (1 % 4)      == "abc"+"abc" -% 'a'          == "abc"+"abc" -% ' '          == "abc"+"abc" -% 'b'          == "abc"+"abc" -% 'A'          == "abc"+"abc" -% 'c'          == "abc"+"abc" -% '\n'         == "abc"+"abc" -% 'd'          == "abc"+"abc" -% '0'          == "abc"+"abc" -% 'e'          == "abc"+"abc" -% 'B'          == "abc"+"abc" -% 'f'          == "abc"+"abc" -% '!'          == "abc"+"abc" -% False        == "abc"+"abc" -% True         == "abc"+
+ tests/diff/examples-b.out view
@@ -0,0 +1,63 @@+"%b" -% ""           == "!"+"%b" -% "a"          == "!"+"%b" -% "aa"         == "!"+"%b" -% " "          == "!"+"%b" -% "aaa"        == "!"+"%b" -% "a "         == "!"+"%b" -% " a"         == "!"+"%b" -% "b"          == "!"+"%b" -% "aaaa"       == "!"+"%b" -% "aa "        == "!"+"%b" -% "a a"        == "!"+"%b" -% "ab"         == "!"+"%b" -% 0            == "0"+"%b" -% 1            == "1"+"%b" -% (-1)         == "-1"+"%b" -% 2            == "10"+"%b" -% (-2)         == "-10"+"%b" -% 3            == "11"+"%b" -% (-3)         == "-11"+"%b" -% 4            == "100"+"%b" -% (-4)         == "-100"+"%b" -% 5            == "101"+"%b" -% (-5)         == "-101"+"%b" -% 6            == "110"+"%b" -% 0.0          == "0"+"%b" -% 1.0          == "1"+"%b" -% 0.5          == "0.1"+"%b" -% (-1.0)       == "-1"+"%b" -% 1.5          == "1.1"+"%b" -% 0.25         == "0.01"+"%b" -% Infinity     == "Infinity"+"%b" -% 2.0          == "10"+"%b" -% (-0.5)       == "-0.1"+"%b" -% 1.25         == "1.01"+"%b" -% 0.75         == "0.11"+"%b" -% (-Infinity)  == "-Infinity"+"%b" -% (0 % 1)      == "0"+"%b" -% (1 % 1)      == "1"+"%b" -% ((-1) % 1)   == "-1"+"%b" -% (1 % 2)      == "0.1"+"%b" -% (2 % 1)      == "10"+"%b" -% ((-1) % 2)   == "-0.1"+"%b" -% ((-2) % 1)   == "-10"+"%b" -% (1 % 3)      == "0"+"%b" -% (3 % 1)      == "11"+"%b" -% ((-1) % 3)   == "-0"+"%b" -% ((-3) % 1)   == "-11"+"%b" -% (1 % 4)      == "0.01"+"%b" -% 'a'          == "!"+"%b" -% ' '          == "!"+"%b" -% 'b'          == "!"+"%b" -% 'A'          == "!"+"%b" -% 'c'          == "!"+"%b" -% '\n'         == "!"+"%b" -% 'd'          == "!"+"%b" -% '0'          == "!"+"%b" -% 'e'          == "!"+"%b" -% 'B'          == "!"+"%b" -% 'f'          == "!"+"%b" -% '!'          == "!"+"%b" -% False        == "!"+"%b" -% True         == "!"+
+ tests/diff/examples-c.out view
@@ -0,0 +1,63 @@+"%c" -% ""           == "!"+"%c" -% "a"          == "!"+"%c" -% "aa"         == "!"+"%c" -% " "          == "!"+"%c" -% "aaa"        == "!"+"%c" -% "a "         == "!"+"%c" -% " a"         == "!"+"%c" -% "b"          == "!"+"%c" -% "aaaa"       == "!"+"%c" -% "aa "        == "!"+"%c" -% "a a"        == "!"+"%c" -% "ab"         == "!"+"%c" -% 0            == "!"+"%c" -% 1            == "!"+"%c" -% (-1)         == "!"+"%c" -% 2            == "!"+"%c" -% (-2)         == "!"+"%c" -% 3            == "!"+"%c" -% (-3)         == "!"+"%c" -% 4            == "!"+"%c" -% (-4)         == "!"+"%c" -% 5            == "!"+"%c" -% (-5)         == "!"+"%c" -% 6            == "!"+"%c" -% 0.0          == "!"+"%c" -% 1.0          == "!"+"%c" -% 0.5          == "!"+"%c" -% (-1.0)       == "!"+"%c" -% 1.5          == "!"+"%c" -% 0.25         == "!"+"%c" -% Infinity     == "!"+"%c" -% 2.0          == "!"+"%c" -% (-0.5)       == "!"+"%c" -% 1.25         == "!"+"%c" -% 0.75         == "!"+"%c" -% (-Infinity)  == "!"+"%c" -% (0 % 1)      == "!"+"%c" -% (1 % 1)      == "!"+"%c" -% ((-1) % 1)   == "!"+"%c" -% (1 % 2)      == "!"+"%c" -% (2 % 1)      == "!"+"%c" -% ((-1) % 2)   == "!"+"%c" -% ((-2) % 1)   == "!"+"%c" -% (1 % 3)      == "!"+"%c" -% (3 % 1)      == "!"+"%c" -% ((-1) % 3)   == "!"+"%c" -% ((-3) % 1)   == "!"+"%c" -% (1 % 4)      == "!"+"%c" -% 'a'          == "a"+"%c" -% ' '          == " "+"%c" -% 'b'          == "b"+"%c" -% 'A'          == "A"+"%c" -% 'c'          == "c"+"%c" -% '\n'         == "\n"+"%c" -% 'd'          == "d"+"%c" -% '0'          == "0"+"%c" -% 'e'          == "e"+"%c" -% 'B'          == "B"+"%c" -% 'f'          == "f"+"%c" -% '!'          == "!"+"%c" -% False        == "!"+"%c" -% True         == "!"+
+ tests/diff/examples-f.out view
@@ -0,0 +1,63 @@+"%f" -% ""           == "!"+"%f" -% "a"          == "!"+"%f" -% "aa"         == "!"+"%f" -% " "          == "!"+"%f" -% "aaa"        == "!"+"%f" -% "a "         == "!"+"%f" -% " a"         == "!"+"%f" -% "b"          == "!"+"%f" -% "aaaa"       == "!"+"%f" -% "aa "        == "!"+"%f" -% "a a"        == "!"+"%f" -% "ab"         == "!"+"%f" -% 0            == "0.0"+"%f" -% 1            == "1.0"+"%f" -% (-1)         == "-1.0"+"%f" -% 2            == "2.0"+"%f" -% (-2)         == "-2.0"+"%f" -% 3            == "3.0"+"%f" -% (-3)         == "-3.0"+"%f" -% 4            == "4.0"+"%f" -% (-4)         == "-4.0"+"%f" -% 5            == "5.0"+"%f" -% (-5)         == "-5.0"+"%f" -% 6            == "6.0"+"%f" -% 0.0          == "0.0"+"%f" -% 1.0          == "1.0"+"%f" -% 0.5          == "0.5"+"%f" -% (-1.0)       == "-1.0"+"%f" -% 1.5          == "1.5"+"%f" -% 0.25         == "0.25"+"%f" -% Infinity     == "Infinity"+"%f" -% 2.0          == "2.0"+"%f" -% (-0.5)       == "-0.5"+"%f" -% 1.25         == "1.25"+"%f" -% 0.75         == "0.75"+"%f" -% (-Infinity)  == "-Infinity"+"%f" -% (0 % 1)      == "0.0"+"%f" -% (1 % 1)      == "1.0"+"%f" -% ((-1) % 1)   == "-1.0"+"%f" -% (1 % 2)      == "0.5"+"%f" -% (2 % 1)      == "2.0"+"%f" -% ((-1) % 2)   == "-0.5"+"%f" -% ((-2) % 1)   == "-2.0"+"%f" -% (1 % 3)      == "0"+"%f" -% (3 % 1)      == "3.0"+"%f" -% ((-1) % 3)   == "-0"+"%f" -% ((-3) % 1)   == "-3.0"+"%f" -% (1 % 4)      == "0.25"+"%f" -% 'a'          == "!"+"%f" -% ' '          == "!"+"%f" -% 'b'          == "!"+"%f" -% 'A'          == "!"+"%f" -% 'c'          == "!"+"%f" -% '\n'         == "!"+"%f" -% 'd'          == "!"+"%f" -% '0'          == "!"+"%f" -% 'e'          == "!"+"%f" -% 'B'          == "!"+"%f" -% 'f'          == "!"+"%f" -% '!'          == "!"+"%f" -% False        == "!"+"%f" -% True         == "!"+
+ tests/diff/examples-i.out view
@@ -0,0 +1,63 @@+"%i" -% ""           == "!"+"%i" -% "a"          == "!"+"%i" -% "aa"         == "!"+"%i" -% " "          == "!"+"%i" -% "aaa"        == "!"+"%i" -% "a "         == "!"+"%i" -% " a"         == "!"+"%i" -% "b"          == "!"+"%i" -% "aaaa"       == "!"+"%i" -% "aa "        == "!"+"%i" -% "a a"        == "!"+"%i" -% "ab"         == "!"+"%i" -% 0            == "0"+"%i" -% 1            == "1"+"%i" -% (-1)         == "-1"+"%i" -% 2            == "2"+"%i" -% (-2)         == "-2"+"%i" -% 3            == "3"+"%i" -% (-3)         == "-3"+"%i" -% 4            == "4"+"%i" -% (-4)         == "-4"+"%i" -% 5            == "5"+"%i" -% (-5)         == "-5"+"%i" -% 6            == "6"+"%i" -% 0.0          == "0"+"%i" -% 1.0          == "1"+"%i" -% 0.5          == "0"+"%i" -% (-1.0)       == "-1"+"%i" -% 1.5          == "2"+"%i" -% 0.25         == "0"+"%i" -% Infinity     == "Infinity"+"%i" -% 2.0          == "2"+"%i" -% (-0.5)       == "-0"+"%i" -% 1.25         == "1"+"%i" -% 0.75         == "1"+"%i" -% (-Infinity)  == "-Infinity"+"%i" -% (0 % 1)      == "0"+"%i" -% (1 % 1)      == "1"+"%i" -% ((-1) % 1)   == "-1"+"%i" -% (1 % 2)      == "0"+"%i" -% (2 % 1)      == "2"+"%i" -% ((-1) % 2)   == "-0"+"%i" -% ((-2) % 1)   == "-2"+"%i" -% (1 % 3)      == "0"+"%i" -% (3 % 1)      == "3"+"%i" -% ((-1) % 3)   == "-0"+"%i" -% ((-3) % 1)   == "-3"+"%i" -% (1 % 4)      == "0"+"%i" -% 'a'          == "!"+"%i" -% ' '          == "!"+"%i" -% 'b'          == "!"+"%i" -% 'A'          == "!"+"%i" -% 'c'          == "!"+"%i" -% '\n'         == "!"+"%i" -% 'd'          == "!"+"%i" -% '0'          == "!"+"%i" -% 'e'          == "!"+"%i" -% 'B'          == "!"+"%i" -% 'f'          == "!"+"%i" -% '!'          == "!"+"%i" -% False        == "!"+"%i" -% True         == "!"+
+ tests/diff/examples-o.out view
@@ -0,0 +1,63 @@+"%o" -% ""           == "!"+"%o" -% "a"          == "!"+"%o" -% "aa"         == "!"+"%o" -% " "          == "!"+"%o" -% "aaa"        == "!"+"%o" -% "a "         == "!"+"%o" -% " a"         == "!"+"%o" -% "b"          == "!"+"%o" -% "aaaa"       == "!"+"%o" -% "aa "        == "!"+"%o" -% "a a"        == "!"+"%o" -% "ab"         == "!"+"%o" -% 0            == "0"+"%o" -% 1            == "1"+"%o" -% (-1)         == "-1"+"%o" -% 2            == "2"+"%o" -% (-2)         == "-2"+"%o" -% 3            == "3"+"%o" -% (-3)         == "-3"+"%o" -% 4            == "4"+"%o" -% (-4)         == "-4"+"%o" -% 5            == "5"+"%o" -% (-5)         == "-5"+"%o" -% 6            == "6"+"%o" -% 0.0          == "0"+"%o" -% 1.0          == "1"+"%o" -% 0.5          == "0.4"+"%o" -% (-1.0)       == "-1"+"%o" -% 1.5          == "1.4"+"%o" -% 0.25         == "0.2"+"%o" -% Infinity     == "Infinity"+"%o" -% 2.0          == "2"+"%o" -% (-0.5)       == "-0.4"+"%o" -% 1.25         == "1.2"+"%o" -% 0.75         == "0.6"+"%o" -% (-Infinity)  == "-Infinity"+"%o" -% (0 % 1)      == "0"+"%o" -% (1 % 1)      == "1"+"%o" -% ((-1) % 1)   == "-1"+"%o" -% (1 % 2)      == "0.4"+"%o" -% (2 % 1)      == "2"+"%o" -% ((-1) % 2)   == "-0.4"+"%o" -% ((-2) % 1)   == "-2"+"%o" -% (1 % 3)      == "0"+"%o" -% (3 % 1)      == "3"+"%o" -% ((-1) % 3)   == "-0"+"%o" -% ((-3) % 1)   == "-3"+"%o" -% (1 % 4)      == "0.2"+"%o" -% 'a'          == "!"+"%o" -% ' '          == "!"+"%o" -% 'b'          == "!"+"%o" -% 'A'          == "!"+"%o" -% 'c'          == "!"+"%o" -% '\n'         == "!"+"%o" -% 'd'          == "!"+"%o" -% '0'          == "!"+"%o" -% 'e'          == "!"+"%o" -% 'B'          == "!"+"%o" -% 'f'          == "!"+"%o" -% '!'          == "!"+"%o" -% False        == "!"+"%o" -% True         == "!"+
+ tests/diff/examples-r.out view
@@ -0,0 +1,63 @@+"%r" -% ""           == "\"\""+"%r" -% "a"          == "\"a\""+"%r" -% "aa"         == "\"aa\""+"%r" -% " "          == "\" \""+"%r" -% "aaa"        == "\"aaa\""+"%r" -% "a "         == "\"a \""+"%r" -% " a"         == "\" a\""+"%r" -% "b"          == "\"b\""+"%r" -% "aaaa"       == "\"aaaa\""+"%r" -% "aa "        == "\"aa \""+"%r" -% "a a"        == "\"a a\""+"%r" -% "ab"         == "\"ab\""+"%r" -% 0            == "0"+"%r" -% 1            == "1"+"%r" -% (-1)         == "-1"+"%r" -% 2            == "2"+"%r" -% (-2)         == "-2"+"%r" -% 3            == "3"+"%r" -% (-3)         == "-3"+"%r" -% 4            == "4"+"%r" -% (-4)         == "-4"+"%r" -% 5            == "5"+"%r" -% (-5)         == "-5"+"%r" -% 6            == "6"+"%r" -% 0.0          == "0.0"+"%r" -% 1.0          == "1.0"+"%r" -% 0.5          == "0.5"+"%r" -% (-1.0)       == "-1.0"+"%r" -% 1.5          == "1.5"+"%r" -% 0.25         == "0.25"+"%r" -% Infinity     == "Infinity"+"%r" -% 2.0          == "2.0"+"%r" -% (-0.5)       == "-0.5"+"%r" -% 1.25         == "1.25"+"%r" -% 0.75         == "0.75"+"%r" -% (-Infinity)  == "-Infinity"+"%r" -% (0 % 1)      == "0 % 1"+"%r" -% (1 % 1)      == "1 % 1"+"%r" -% ((-1) % 1)   == "(-1) % 1"+"%r" -% (1 % 2)      == "1 % 2"+"%r" -% (2 % 1)      == "2 % 1"+"%r" -% ((-1) % 2)   == "(-1) % 2"+"%r" -% ((-2) % 1)   == "(-2) % 1"+"%r" -% (1 % 3)      == "1 % 3"+"%r" -% (3 % 1)      == "3 % 1"+"%r" -% ((-1) % 3)   == "(-1) % 3"+"%r" -% ((-3) % 1)   == "(-3) % 1"+"%r" -% (1 % 4)      == "1 % 4"+"%r" -% 'a'          == "'a'"+"%r" -% ' '          == "' '"+"%r" -% 'b'          == "'b'"+"%r" -% 'A'          == "'A'"+"%r" -% 'c'          == "'c'"+"%r" -% '\n'         == "'\\n'"+"%r" -% 'd'          == "'d'"+"%r" -% '0'          == "'0'"+"%r" -% 'e'          == "'e'"+"%r" -% 'B'          == "'B'"+"%r" -% 'f'          == "'f'"+"%r" -% '!'          == "'!'"+"%r" -% False        == "False"+"%r" -% True         == "True"+
+ tests/diff/examples-s.out view
@@ -0,0 +1,63 @@+"%s" -% ""           == ""+"%s" -% "a"          == "a"+"%s" -% "aa"         == "aa"+"%s" -% " "          == " "+"%s" -% "aaa"        == "aaa"+"%s" -% "a "         == "a "+"%s" -% " a"         == " a"+"%s" -% "b"          == "b"+"%s" -% "aaaa"       == "aaaa"+"%s" -% "aa "        == "aa "+"%s" -% "a a"        == "a a"+"%s" -% "ab"         == "ab"+"%s" -% 0            == "0"+"%s" -% 1            == "1"+"%s" -% (-1)         == "-1"+"%s" -% 2            == "2"+"%s" -% (-2)         == "-2"+"%s" -% 3            == "3"+"%s" -% (-3)         == "-3"+"%s" -% 4            == "4"+"%s" -% (-4)         == "-4"+"%s" -% 5            == "5"+"%s" -% (-5)         == "-5"+"%s" -% 6            == "6"+"%s" -% 0.0          == "0.0"+"%s" -% 1.0          == "1.0"+"%s" -% 0.5          == "0.5"+"%s" -% (-1.0)       == "-1.0"+"%s" -% 1.5          == "1.5"+"%s" -% 0.25         == "0.25"+"%s" -% Infinity     == "Infinity"+"%s" -% 2.0          == "2.0"+"%s" -% (-0.5)       == "-0.5"+"%s" -% 1.25         == "1.25"+"%s" -% 0.75         == "0.75"+"%s" -% (-Infinity)  == "-Infinity"+"%s" -% (0 % 1)      == "0 % 1"+"%s" -% (1 % 1)      == "1 % 1"+"%s" -% ((-1) % 1)   == "(-1) % 1"+"%s" -% (1 % 2)      == "1 % 2"+"%s" -% (2 % 1)      == "2 % 1"+"%s" -% ((-1) % 2)   == "(-1) % 2"+"%s" -% ((-2) % 1)   == "(-2) % 1"+"%s" -% (1 % 3)      == "1 % 3"+"%s" -% (3 % 1)      == "3 % 1"+"%s" -% ((-1) % 3)   == "(-1) % 3"+"%s" -% ((-3) % 1)   == "(-3) % 1"+"%s" -% (1 % 4)      == "1 % 4"+"%s" -% 'a'          == "'a'"+"%s" -% ' '          == "' '"+"%s" -% 'b'          == "'b'"+"%s" -% 'A'          == "'A'"+"%s" -% 'c'          == "'c'"+"%s" -% '\n'         == "'\\n'"+"%s" -% 'd'          == "'d'"+"%s" -% '0'          == "'0'"+"%s" -% 'e'          == "'e'"+"%s" -% 'B'          == "'B'"+"%s" -% 'f'          == "'f'"+"%s" -% '!'          == "'!'"+"%s" -% False        == "False"+"%s" -% True         == "True"+
+ tests/diff/examples-x.out view
@@ -0,0 +1,63 @@+"%x" -% ""           == "!"+"%x" -% "a"          == "!"+"%x" -% "aa"         == "!"+"%x" -% " "          == "!"+"%x" -% "aaa"        == "!"+"%x" -% "a "         == "!"+"%x" -% " a"         == "!"+"%x" -% "b"          == "!"+"%x" -% "aaaa"       == "!"+"%x" -% "aa "        == "!"+"%x" -% "a a"        == "!"+"%x" -% "ab"         == "!"+"%x" -% 0            == "0"+"%x" -% 1            == "1"+"%x" -% (-1)         == "-1"+"%x" -% 2            == "2"+"%x" -% (-2)         == "-2"+"%x" -% 3            == "3"+"%x" -% (-3)         == "-3"+"%x" -% 4            == "4"+"%x" -% (-4)         == "-4"+"%x" -% 5            == "5"+"%x" -% (-5)         == "-5"+"%x" -% 6            == "6"+"%x" -% 0.0          == "0"+"%x" -% 1.0          == "1"+"%x" -% 0.5          == "0.8"+"%x" -% (-1.0)       == "-1"+"%x" -% 1.5          == "1.8"+"%x" -% 0.25         == "0.4"+"%x" -% Infinity     == "Infinity"+"%x" -% 2.0          == "2"+"%x" -% (-0.5)       == "-0.8"+"%x" -% 1.25         == "1.4"+"%x" -% 0.75         == "0.c"+"%x" -% (-Infinity)  == "-Infinity"+"%x" -% (0 % 1)      == "0"+"%x" -% (1 % 1)      == "1"+"%x" -% ((-1) % 1)   == "-1"+"%x" -% (1 % 2)      == "0.8"+"%x" -% (2 % 1)      == "2"+"%x" -% ((-1) % 2)   == "-0.8"+"%x" -% ((-2) % 1)   == "-2"+"%x" -% (1 % 3)      == "0"+"%x" -% (3 % 1)      == "3"+"%x" -% ((-1) % 3)   == "-0"+"%x" -% ((-3) % 1)   == "-3"+"%x" -% (1 % 4)      == "0.4"+"%x" -% 'a'          == "!"+"%x" -% ' '          == "!"+"%x" -% 'b'          == "!"+"%x" -% 'A'          == "!"+"%x" -% 'c'          == "!"+"%x" -% '\n'         == "!"+"%x" -% 'd'          == "!"+"%x" -% '0'          == "!"+"%x" -% 'e'          == "!"+"%x" -% 'B'          == "!"+"%x" -% 'f'          == "!"+"%x" -% '!'          == "!"+"%x" -% False        == "!"+"%x" -% True         == "!"+
+ tests/diff/examples.out view
@@ -0,0 +1,63 @@+"%r" -% ""           == "\"\""+"%r" -% "a"          == "\"a\""+"%r" -% "aa"         == "\"aa\""+"%r" -% " "          == "\" \""+"%r" -% "aaa"        == "\"aaa\""+"%r" -% "a "         == "\"a \""+"%r" -% " a"         == "\" a\""+"%r" -% "b"          == "\"b\""+"%r" -% "aaaa"       == "\"aaaa\""+"%r" -% "aa "        == "\"aa \""+"%r" -% "a a"        == "\"a a\""+"%r" -% "ab"         == "\"ab\""+"%r" -% 0            == "0"+"%r" -% 1            == "1"+"%r" -% (-1)         == "-1"+"%r" -% 2            == "2"+"%r" -% (-2)         == "-2"+"%r" -% 3            == "3"+"%r" -% (-3)         == "-3"+"%r" -% 4            == "4"+"%r" -% (-4)         == "-4"+"%r" -% 5            == "5"+"%r" -% (-5)         == "-5"+"%r" -% 6            == "6"+"%r" -% 0.0          == "0.0"+"%r" -% 1.0          == "1.0"+"%r" -% 0.5          == "0.5"+"%r" -% (-1.0)       == "-1.0"+"%r" -% 1.5          == "1.5"+"%r" -% 0.25         == "0.25"+"%r" -% Infinity     == "Infinity"+"%r" -% 2.0          == "2.0"+"%r" -% (-0.5)       == "-0.5"+"%r" -% 1.25         == "1.25"+"%r" -% 0.75         == "0.75"+"%r" -% (-Infinity)  == "-Infinity"+"%r" -% (0 % 1)      == "0 % 1"+"%r" -% (1 % 1)      == "1 % 1"+"%r" -% ((-1) % 1)   == "(-1) % 1"+"%r" -% (1 % 2)      == "1 % 2"+"%r" -% (2 % 1)      == "2 % 1"+"%r" -% ((-1) % 2)   == "(-1) % 2"+"%r" -% ((-2) % 1)   == "(-2) % 1"+"%r" -% (1 % 3)      == "1 % 3"+"%r" -% (3 % 1)      == "3 % 1"+"%r" -% ((-1) % 3)   == "(-1) % 3"+"%r" -% ((-3) % 1)   == "(-3) % 1"+"%r" -% (1 % 4)      == "1 % 4"+"%r" -% 'a'          == "'a'"+"%r" -% ' '          == "' '"+"%r" -% 'b'          == "'b'"+"%r" -% 'A'          == "'A'"+"%r" -% 'c'          == "'c'"+"%r" -% '\n'         == "'\\n'"+"%r" -% 'd'          == "'d'"+"%r" -% '0'          == "'0'"+"%r" -% 'e'          == "'e'"+"%r" -% 'B'          == "'B'"+"%r" -% 'f'          == "'f'"+"%r" -% '!'          == "'!'"+"%r" -% False        == "False"+"%r" -% True         == "True"+
+ tests/test-number.hs view
@@ -0,0 +1,186 @@+-- Copyright (c) 2018 Rudy Matela.+-- Distributed under the 3-Clause BSD licence (see the file LICENSE).+import Test++import Text.PercentFormat+import Text.PercentFormat.Quotient (Quotient)+import Data.List (isInfixOf)++import qualified Data.Ratio as R++main :: IO ()+main = reportTests tests++tests :: [Bool]+tests =+  [ True++  -- single digits, positives+  , "%i" % 1 == "1"+  , "%d" % 2 == "2"+  , "%x" % 3 == "3"+  , "%o" % 4 == "4"+  , "%b" % 5 == "101"+  , "%f" % 6 == "6.0"++  -- double digits, positives+  , "%i" % 12 == "12"+  , "%d" % 23 == "23"+  , "%x" % 34 == "22"+  , "%o" % 45 == "55"+  , "%b" % 56 == "111000"+  , "%f" % 67 == "67.0"++  -- single digits, negatives+  , "%i" % (-1) == "-1"+  , "%d" % (-2) == "-2"+  , "%x" % (-3) == "-3"+  , "%o" % (-4) == "-4"+  , "%b" % (-5) == "-101"+  , "%f" % (-6) == "-6.0"++  -- double digits, negatives+  , "%i" % (-12) == "-12"+  , "%d" % (-23) == "-23"+  , "%x" % (-34) == "-22"+  , "%o" % (-45) == "-55"+  , "%b" % (-56) == "-111000"+  , "%f" % (-67) == "-67.0"++  -- Infinity+  , "%f" % (1.0 / 0.0) == "Infinity"+  , "%i" % (1.0 / 0.0) == "Infinity"+  , "%d" % (1.0 / 0.0) == "Infinity"+  , "%x" % (1.0 / 0.0) == "Infinity"+  , "%o" % (1.0 / 0.0) == "Infinity"+  , and $ [ "%%%i%c" -%% (n,c) -% (1.0 / 0.0) == "Infinity"+          | n <- [-7..7], c <- "idxobf" ]++  -- -Infinity+  , "%f" % (-1.0 / 0.0) == "-Infinity"+  , "%i" % (-1.0 / 0.0) == "-Infinity"+  , "%d" % (-1.0 / 0.0) == "-Infinity"+  , "%x" % (-1.0 / 0.0) == "-Infinity"+  , "%o" % (-1.0 / 0.0) == "-Infinity"++  -- NaN+  , "%f" % (0.0 / 0.0) == "NaN"+  , "%i" % (0.0 / 0.0) == "NaN"+  , "%d" % (0.0 / 0.0) == "NaN"+  , "%x" % (0.0 / 0.0) == "NaN"+  , "%o" % (0.0 / 0.0) == "NaN"+  , and $ [ "NaN" `isInfixOf` ("%%%i%c" -%% (n,c) -% (0.0 / 0.0))+          | n <- [-7..7], c <- "idxobf" ]++  -- decimal fractional digits+  , "%f" % 1 == "1.0"+  , "%f" % 1.1 == "1.1"+  , "%f" % (10.0 / 3.0) == show (10.0 / 3.0)+  , "%.3f" % (10.0 / 3.0) == "3.333"+  , "%1.2f" % 1.1 == "1.10"+  , "%06.3f" % 1.23 == "01.230"+  , "%.1f" % 1.14 == "1.1"+  , "%.3f" % (-1.2) == "-1.200"+  , "%.1f" % 1.16 == "1.2"+  , "%.1f" % 1.15 == "1.2"  -- round to the nearest even number+  , "%.1f" % 1.25 == "1.2"  -- round to the nearest even number+  , "%15.7f" % 1234567.1234567 == "1234567.1234567"+  , "%17.8f" % (12345678.12345678 :: Quotient) == "12345678.12345678"+--, "%17.8f" % 12345678.12345678 == "12345678.12345678"  -- GHC+--, "%17.8f" % 12345678.12345678 == "12345678.12345680"  -- Hugs++  -- fractional digits in other bases+  , "%.2x" % (1.0 / 200.0) == "0.01"+  , "%.2x" % (3.0 / 200.0) == "0.04"+  , "%.8b" % (1.0 / 200.0) == "0.00000001"+  , "%.8b" % (3.0 / 200.0) == "0.00000100"+  , "%.1x" % (3.0 / 2.0) == "1.8"+  , "%.1b" % (3.0 / 2.0) == "1.1"+  , "%.0b" % (3.0 / 2.0) == "10"+  , "%.0b" % (1.0 / 2.0) == "0"++  -- %i rounds to the nearest integer, unless precision is specified+  , "%i"   % 3.1 == "3"+  , "%.*i" % 3.1 == "3.1"+  , "%.2i" % 3.1 == "3.10"+  , "%.*i" % 3.141 == "3.141"+  , "%.2i" % 3.141 == "3.14"++  -- %f shows a minimum of one fractional digit+  , "%f" % 6 == "6.0"+  , "%f" % 12 == "12.0"++  -- positive/negative signal placement+  , "%+i" % 1 == "+1"+  , "% i" % 1 == " 1"+  , "%+f" % 1.2 == "+1.2"+  , "% f" % 1.2 == " 1.2"+  , "%3d" % (-1) == " -1"+  , "%4d" % (-1) == "  -1"+  , "%03d" % (-1) == "-01"+  , "%04d" % (-1) == "-001"+  , "%+3d" % 1 == " +1"+  , "%+4d" % 1 == "  +1"+  , "%+03d" % 1 == "+01"+  , "%+04d" % 1 == "+001"+  , "% 07.3f" %   3.3  == " 03.300"+  , "% 07.3f" % (-3.3) == "-03.300"+  , "% 7.3f"  %   3.3  == "  3.300"+  , "% 7.3f"  % (-3.3) == " -3.300"++  , "%07.3d" -% 10.5 == "010.500"+  , "%07.3x" -% 10.5 == "00a.800"+  , "%07.3b" -% 10.5 == "1010.100"++  -- Ratios+  , "asdf %r qwer" -% (10 R.% 3) == "asdf 10 % 3 qwer"+  , "asdf %07.3f qwer" -% (10 R.% 3) == "asdf 003.333 qwer"++  , "%x" -% 0xfedcba9876543210 == "fedcba9876543210"+  , "%X" -% 0xFEDCBA9876543210 == "FEDCBA9876543210"++  , "%i"    % pi == "3"+  , "%.8d"  % pi == "3.14159265"+--, "%d"    % pi == "3.14159265358979"   -- Hugs+--, "%d"    % pi == "3.141592653589793"  -- GHC+  , "%.8x" % pi == "3.243f6a89"+  , "%.12b" % pi == "11.001001000100"+++-- TODO: in the future, also handle Ratios nicely:+-- NOTE: use 360 or 5040 as a default divisor (max precision)+-- '/' can be just an alias for '.'+--, "%q" % (2/3 :: Rational) == "2/3"+--, "%q" % (2/3 :: Rational) == "2/3"+--, "%Q" % (2/3 :: Rational) == "2 % 3"+--, "%q" % 0.333 == "1/3"+--, "%q" % 0 == "0/1"+--, "%q" % 1 == "1/1"+--, "%q" % 2 == "2/1"+--, "%/12q" % 0.333 == "1/3"+--, "%/3q" % (3/12) == "1/3"+--, "%4/3q" % (3/12) == " 1/3"+-- why not use /N for exact precision?+-- one can just format manually using %i/%i+-- or even use %/*q++  -- error handling+  , "%i"   % "a" == "!"+  , "%d"   % "a" == "!"+  , "%x"   % "a" == "!"+  , "%o"   % "a" == "!"+  , "%b"   % "a" == "!"+  , "%f"   % "a" == "!"+  , "%1i"  % "b" == "!"+  , "%2d"  % "c" == "!!"+  , "%3x"  % " " == "!!!"+  , "%4o"  % "!" == "!!!!"+  , "%5b"  % "." == "!!!!!"+  , "%6f"  % "-" == "!!!!!!"+  , "%01f" % "A" == "!"+  , "%02b" % "B" == "!!"+  , "%03o" % "C" == "!!!"+  , "%04x" % "%" == "!!!!"+  , "%05d" % "/" == "!!!!!"+  , "%06i" % "^" == "!!!!!!"+  ]
+ tests/test-prop.hs view
@@ -0,0 +1,26 @@+-- Copyright (c) 2018 Rudy Matela.+-- Distributed under the 3-Clause BSD licence (see the file LICENSE).+import Test+import Text.PercentFormat+import Test.LeanCheck++main :: IO ()+main = reportTests (tests 10000)++tests :: Int -> [Bool]+tests n =+  [ True+  , holds n $ \s -> s == "%s" -% s+  , holds n $ \s t -> s ++ t == "%s%s" % s -% t+  , holds n $ \s t -> s ++ "%" ++ t == "%s%%%s" % s -% t+  , holds n $ \s -> s ++ s == "%s%s" % s -% s+  , holds n $ \s1 s2 s3 -> s1 ++ s2 ++ s3 == (s1 ++ "%s" ++ s3) -% s2+  , holds n $ \s -> show s == "%r" -% (s::String)+  , holds n $ \x -> show x == "%r" -% (x::Int)+  , holds n $ \c -> show c == "%r" -% (c::Char)+  , holds n $ \f -> show f == "%r" -% (f::Float)+  , holds n $ \i -> show i == "%i" -% (i::Int)+  , holds n $ \f -> 'e' `notElem` show f -- TODO: == %f or == %e+                ==> show f == "%f" -% (f::Float)+  , holds n $ \c -> c:""   == "%c" -% (c::Char)+  ]
+ tests/test-quotient.hs view
@@ -0,0 +1,56 @@+-- Copyright (c) 2018 Rudy Matela.+-- Distributed under the 3-Clause BSD licence (see the file LICENSE).+import Test++import Test.LeanCheck+import Test.LeanCheck.Utils++import Text.PercentFormat.Quotient as Q+import Text.PercentFormat.Utils++quotient :: Quotient+quotient  =  error "dummy quotient value"++instance Listable Quotient where+  tiers  =  mapT (uncurry (Q.%)) . reset+         $  tiers `suchThat` canonical+    where+    --canonical (0,0)  =  True+    --canonical (1,0)  =  True+    canonical (n,d)  =  d > 0 && n `gcd` d == 1++main :: IO ()+main = reportTests (tests 360)++tests :: Int -> [Bool]+tests n =+  [ True++  , holds n $ commutative ((+) -:> quotient)+  , holds n $ associative ((+) -:> quotient)+  , holds n $ commutative ((*) -:> quotient)+  , holds n $ associative ((*) -:> quotient)+  , holds n $ distributive (*) ((+) -:> quotient)+  , holds n $ idempotent (+0) -:> quotient+  , holds n $ idempotent (*1) -:> quotient+  , holds n $ idempotent abs -:> quotient+  , holds n $ idempotent signum -:> quotient+  , holds n $ \x -> negate (negate x) == (x -: quotient)+  , holds n $ \x -> abs x * signum x == (x -: quotient)++  , holds n $ \q r s -> none Q.isNaN [q,r,s] ==> okEqOrd q r s+--, holds n $ okNum -:> quotient  -- TODO: when new LeanCheck is released++  , readQ "Infinity" == infinity+  , readQ "-Infinity" == -infinity+  , let nan' = readQ "NaN" in nan' /= nan'+  , maybeReadQ "blah" == Nothing+  , readQ "10" == 10+  , readQ "-300" == (-300)+  , readQ "10.10" == 101 % 10+  , readQ "10.1" == 101 % 10+  , readQ "33.3e2" == 3330+  , readQ "3.33e2" == 333+  , round (1/2 :: Quotient) == 0+  , round (3/2 :: Quotient) == 2+  ]
+ tests/test-scientific.hs view
@@ -0,0 +1,56 @@+-- Copyright (c) 2018 Rudy Matela.+-- Distributed under the 3-Clause BSD licence (see the file LICENSE).+import Test++import Text.PercentFormat+import Data.List (isInfixOf)++import qualified Data.Ratio as R++main :: IO ()+main = reportTests tests++tests :: [Bool]+tests =+  [ True++{-+  -- TODO: make the following pass:+  , "%e" -% 0 == "0.0e0"+  , "%e" -% 1 == "1.0e0"+  , "%e" -% 2 == "2.0e0"+  , "%e" -% 0.1   == "1.0e-1"+  , "%e" -% 0.12  == "1.2e-1"+  , "%e" -% 0.123 == "1.23e-1"+  , "%e" -% 1.0   == "1.0e0"+  , "%e" -% 1.2   == "1.2e0"+  , "%e" -% 1.23  == "1.23e0"+  , "%e" -% 10.0  == "1.0e1"+  , "%e" -% 12.0  == "1.2e1"+  , "%e" -% 12.3  == "1.23e1"+  , "%.1e" -% 0     == "0.0e0"+  , "%.1e" -% 1     == "1.0e0"+  , "%.1e" -% 2     == "2.0e0"+  , "%.1e" -% 0.1   == "1.0e-1"+  , "%.1e" -% 0.12  == "1.2e-1"+  , "%.1e" -% 0.123 == "1.2e-1"+  , "%.1e" -% 1.0   == "1.0e0"+  , "%.1e" -% 1.2   == "1.2e0"+  , "%.1e" -% 1.23  == "1.2e0"+  , "%.1e" -% 10.0  == "1.0e1"+  , "%.1e" -% 12.0  == "1.2e1"+  , "%.1e" -% 12.3  == "1.2e1"+  , "%.2e" -% 0     == "0.00e0"+  , "%.2e" -% 1     == "1.00e0"+  , "%.2e" -% 2     == "2.00e0"+  , "%.2e" -% 0.1   == "1.00e-1"+  , "%.2e" -% 0.12  == "1.20e-1"+  , "%.2e" -% 0.123 == "1.23e-1"+  , "%.2e" -% 1.0   == "1.00e0"+  , "%.2e" -% 1.2   == "1.20e0"+  , "%.2e" -% 1.23  == "1.23e0"+  , "%.2e" -% 10.0  == "1.00e1"+  , "%.2e" -% 12.0  == "1.20e1"+  , "%.2e" -% 12.3  == "1.23e1"+-}+  ]
+ tests/test-sdist view
@@ -0,0 +1,31 @@+#!/bin/bash+#+# test-sdist: tests the package generated by "cabal sdist".+#+# Copyright (c) 2015-2018 Rudy Matela.+# Distributed under the 3-Clause BSD licence.+#+# TODO: also run "make test"+# TODO: also run "stack test"+pkgver=` cat *.cabal | grep "^version:" | sed -e "s/version: *//"`+pkgname=`cat *.cabal | grep "^name:"    | sed -e "s/name: *//"`+pkg=$pkgname-$pkgver+set -x+cabal sdist &&+cd dist &&+rm -rf $pkg/ &&+tar -xzf $pkg.tar.gz &&+cd $pkg/ &&+cabal configure --enable-tests --enable-benchmarks &&+cabal build &&+cabal test &&+cd .. &&+if [ -d ../.git ]+then+	git -C .. ls-files                                      | sort > ls-git   &&+	tar -tf $pkg.tar.gz | grep -v "/$" | sed -e "s,$pkg/,," | sort > ls-cabal &&+	diff -rud ls-git ls-cabal &&+	rm -f ls-git ls-cabal+else+	true # skip test+fi
+ tests/test-spec.hs view
@@ -0,0 +1,48 @@+-- Copyright (c) 2018 Rudy Matela.+-- Distributed under the 3-Clause BSD licence (see the file LICENSE).+import Test++import Text.PercentFormat.Spec++main :: IO ()+main = reportTests tests++tests :: [Bool]+tests =+  [ True+  , parseSpec "%"    ==- spec {ty = Percent}+  , parseSpec "r"    ==- spec {ty = ReprSpec}+  , parseSpec "s"    ==- spec {ty = StringSpec}+  , parseSpec "10s"  ==- spec {ty = StringSpec,  width = 10}+  , parseSpec "21s"  ==- spec {ty = StringSpec,  width = 21}+  , parseSpec "d"    ==- spec {ty = NumberSpec}+  , parseSpec "4d"   ==- spec {ty = NumberSpec, width =  4,  base = 10}+  , parseSpec "6d"   ==- spec {ty = NumberSpec, width =  6,  base = 10}+  , parseSpec "07d"  ==- spec {ty = NumberSpec, width =  7,  padWith = '0'}+  , parseSpec "073d" ==- spec {ty = NumberSpec, width =  73, padWith = '0'}+  , parseSpec "6i"   ==- spec {ty = NumberSpec, width =  6,  base = 10, precision = Just 0}+  , parseSpec "07i"  ==- spec {ty = NumberSpec, width =  7,  padWith = '0', precision = Just 0}+  , parseSpec "07.*i" ==- spec {ty = NumberSpec, width =  7,  padWith = '0'}+  , parseSpec "073i" ==- spec {ty = NumberSpec, width =  73, padWith = '0', precision = Just 0}+  , parseSpec "x"    ==- spec {ty = NumberSpec, base = 16}+  , parseSpec "X"    ==- spec {ty = NumberSpec, base = 16, capitalizeDigits = True}+  , parseSpec "o"    ==- spec {ty = NumberSpec, base =  8}+  , parseSpec "b"    ==- spec {ty = NumberSpec, base =  2}+  , parseSpec "d"    ==- spec {ty = NumberSpec, positivePrefix=""}+  , parseSpec "+d"   ==- spec {ty = NumberSpec, positivePrefix="+"}+  , parseSpec " d"   ==- spec {ty = NumberSpec, positivePrefix=" "}+  , parseSpec "i"    ==- spec {ty = NumberSpec, positivePrefix="", precision = Just 0}+  , parseSpec "+i"   ==- spec {ty = NumberSpec, positivePrefix="+", precision = Just 0}+  , parseSpec " i"   ==- spec {ty = NumberSpec, positivePrefix=" ", precision = Just 0}+  , parseSpec ".*i"  ==- spec {ty = NumberSpec, positivePrefix=""}+  , parseSpec "f"    ==- spec {ty = NumberSpec, minPrecision = 1}+  , parseSpec "3f"   ==- spec {ty = NumberSpec, minPrecision = 1, width = 3}+  , parseSpec "4.1f" ==- spec {ty = NumberSpec, minPrecision = 1, width = 4, precision = Just 1}+  , parseSpec "4.0f" ==- spec {ty = NumberSpec, minPrecision = 1, width = 4, precision = Just 0}+  , parseSpec "4.f"  ==- spec {ty = NumberSpec, minPrecision = 1, width = 4, precision = Just 0}+  , parseSpec "f"    ==- spec {ty = NumberSpec, minPrecision = 1, positivePrefix=""}+  , parseSpec "+f"   ==- spec {ty = NumberSpec, minPrecision = 1, positivePrefix="+"}+  , parseSpec " f"   ==- spec {ty = NumberSpec, minPrecision = 1, positivePrefix=" "}+    ]+  where+  x ==- y = x == (y,"")
+ tests/test-unit.hs view
@@ -0,0 +1,49 @@+-- Copyright (c) 2018 Rudy Matela.+-- Distributed under the 3-Clause BSD licence (see the file LICENSE).+import Test++import Text.PercentFormat++main :: IO ()+main = reportTests tests++tests :: [Bool]+tests =+  [ True++  , "asdf qwer"      % "asdf" ==  "asdf qwer"+  , "zxcv qwer"      % "asdf" ==  "zxcv qwer"+  , "asdf %s qwer"   % "asdf" ==  "asdf asdf qwer"+  , "asdf %5s qwer"  % "asdf" ==  "asdf  asdf qwer"+  , "asdf %5-s qwer" % "asdf" ==  "asdf asdf  qwer"+  , "%s" % "1%" == "1%%"+  , "%s" -% "1%" == "1%"++  , "asdf %d qwer"   % 10     ==  "asdf 10 qwer"+  , "asdf %2d qwer"  %  9     ==  "asdf  9 qwer"+  , "asdf %02d qwer" %  9     ==  "asdf 09 qwer"+  , "asdf %012d qwer" % 123   ==  "asdf 000000000123 qwer"++  , "asdf %x qwer" % 10       ==  "asdf a qwer"+  , "asdf %04x qwer" % 10     ==  "asdf 000a qwer"+  , "asdf %o qwer"   % 10     ==  "asdf 12 qwer"+  , "asdf %03o qwer" % 10     ==  "asdf 012 qwer"+  , "%b" % 10 == "1010"+  , "%08b" % 10 == "00001010"+  , "asdf %X qwer" % 10       ==  "asdf A qwer"++  , "%c" % 'c' == "c"+  , "%r" % 'c' == "'c'"++  , "%s" % 10 == "10"++  , "%c"   % "a" == "!"+  , "%c"   % 3   == "!"+  , "%c"   % 3.1 == "!"++  -- not really error:+  , "%s"   % 0    == "0"+  , "%s"   % 3.14 == "3.14"+  , "%2s"  % 0    == " 0"+  , "%2s"  % 3.14 == "3.14"+  ]