boxes 0.1.4 → 0.1.5
raw patch · 5 files changed
+141/−71 lines, 5 filesdep ~base
Dependency ranges changed: base
Files
- CHANGES +8/−1
- Text/PrettyPrint/Boxes.hs +38/−40
- Text/PrettyPrint/Tests.hs +48/−23
- boxes.cabal +7/−7
- include/boxes.h +40/−0
CHANGES view
@@ -1,4 +1,11 @@-0.1.4: January 14, 2014+0.1.5: March 10, 2018+ * Add support for GHC 8.4.1. Thanks, Andrés Sicard-Ramírez.+ * Clean up QuickCheck generators, and prevent them from blowing up.+ Thanks, Harry Garrood.+ * Generalize functions for combining multiple boxes from lists to+ `Foldable` containers.++0.1.4: January 14, 2015 * Require Cabal >= 1.9.2 * Require CPP * Only require OverloadedStrings for GHC
Text/PrettyPrint/Boxes.hs view
@@ -1,31 +1,12 @@ {-# LANGUAGE CPP #-}-#ifndef MIN_VERSION_base--- These are not precise, but allow the module to be built without cabal.-#if __GLASGOW_HASKELL__ >= 709-#define MIN_VERSION_base(major1,major2,minor) (((major1) <= 4) && ((major2) <= 8))-#elif __GLASGOW_HASKELL__ >= 707-#define MIN_VERSION_base(major1,major2,minor) (((major1) <= 4) && ((major2) <= 7))-#elif __GLASGOW_HASKELL__ >= 706-#define MIN_VERSION_base(major1,major2,minor) (((major1) <= 4) && ((major2) <= 6))-#else-#define MIN_VERSION_base(major1,major2,minor) 0-#endif-#endif--#ifdef __GLASGOW_HASKELL__-#define OVERLOADED_STRINGS 1-#endif--#ifdef OVERLOADED_STRINGS-{-# LANGUAGE OverloadedStrings #-}-#endif+#include "boxes.h" ----------------------------------------------------------------------------- -- | -- Module : Text.PrettyPrint.Boxes -- Copyright : (c) Brent Yorgey 2009 -- License : BSD-style (see LICENSE)--- Maintainer : byorgey@cis.upenn.edu+-- Maintainer : David.Feuer@gmail.com -- Stability : experimental -- Portability : portable --@@ -97,9 +78,15 @@ ) where -#if MIN_VERSION_base(4,8,0)+#if MIN_VERSION_base(4,11,0)+import Prelude hiding ( (<>), Word )+#elif MIN_VERSION_base(4,8,0) import Prelude hiding (Word)+#else+import Data.Foldable (Foldable (foldr))+import Prelude hiding (foldr) #endif+import Data.Foldable (toList) #if MIN_VERSION_base(4,4,0) import Data.String (words, unwords)@@ -213,35 +200,46 @@ t /+/ b = vcat left [t, emptyBox 1 0, b] -- | Glue a list of boxes together horizontally, with the given alignment.-hcat :: Alignment -> [Box] -> Box-hcat a bs = Box h w (Row $ map (alignVert a h) bs)- where h = maximum . (0:) . map rows $ bs- w = sum . map cols $ bs+hcat :: Foldable f => Alignment -> f Box -> Box+hcat a bs = Box h w (Row $ map (alignVert a h) bsl)+ where+ (w, h) = sumMax cols 0 rows bsl+ bsl = toList bs -- | @hsep sep a bs@ lays out @bs@ horizontally with alignment @a@, -- with @sep@ amount of space in between each.-hsep :: Int -> Alignment -> [Box] -> Box+hsep :: Foldable f => Int -> Alignment -> f Box -> Box hsep sep a bs = punctuateH a (emptyBox 0 sep) bs -- | Glue a list of boxes together vertically, with the given alignment.-vcat :: Alignment -> [Box] -> Box-vcat a bs = Box h w (Col $ map (alignHoriz a w) bs)- where h = sum . map rows $ bs- w = maximum . (0:) . map cols $ bs+vcat :: Foldable f => Alignment -> f Box -> Box+vcat a bs = Box h w (Col $ map (alignHoriz a w) bsl)+ where+ (h, w) = sumMax rows 0 cols bsl+ bsl = toList bs +-- Calculate a sum and a maximum over a list in one pass. If the list is+-- empty, the maximum is reported as the given default. This would+-- normally be done using the foldl library, but we don't want that+-- dependency.+sumMax :: (Num n, Ord b, Foldable f) => (a -> n) -> b -> (a -> b) -> f a -> (n, b)+sumMax f defaultMax g as = foldr go (,) as 0 defaultMax+ where+ go a r n b = (r $! f a + n) $! g a `max` b+ -- | @vsep sep a bs@ lays out @bs@ vertically with alignment @a@, -- with @sep@ amount of space in between each.-vsep :: Int -> Alignment -> [Box] -> Box-vsep sep a bs = punctuateV a (emptyBox sep 0) bs+vsep :: Foldable f => Int -> Alignment -> f Box -> Box+vsep sep a bs = punctuateV a (emptyBox sep 0) (toList bs) -- | @punctuateH a p bs@ horizontally lays out the boxes @bs@ with a -- copy of @p@ interspersed between each.-punctuateH :: Alignment -> Box -> [Box] -> Box-punctuateH a p bs = hcat a (intersperse p bs)+punctuateH :: Foldable f => Alignment -> Box -> f Box -> Box+punctuateH a p bs = hcat a (intersperse p (toList bs)) -- | A vertical version of 'punctuateH'.-punctuateV :: Alignment -> Box -> [Box] -> Box-punctuateV a p bs = vcat a (intersperse p bs)+punctuateV :: Foldable f => Alignment -> Box -> f Box -> Box+punctuateV a p bs = vcat a (intersperse p (toList bs)) -------------------------------------------------------------------------------- -- Paragraph flowing ---------------------------------------------------------@@ -289,7 +287,7 @@ data Line = Line { lLen :: Int, getWords :: [Word] } mkLine :: [Word] -> Line-mkLine ws = Line (sum (map wLen ws) + length ws - 1) ws+mkLine ws = Line (sum (map ((+1) . wLen) ws) - 1) ws startLine :: Word -> Line startLine = mkLine . (:[])@@ -318,13 +316,13 @@ -- contents and height of @bx@, horizontally aligned according to -- @algn@. alignHoriz :: Alignment -> Int -> Box -> Box-alignHoriz a c b = Box (rows b) c $ SubBox a AlignFirst b+alignHoriz a c b = align a AlignFirst (rows b) c b -- | @alignVert algn n bx@ creates a box of height @n@, with the -- contents and width of @bx@, vertically aligned according to -- @algn@. alignVert :: Alignment -> Int -> Box -> Box-alignVert a r b = Box r (cols b) $ SubBox AlignFirst a b+alignVert a r b = align AlignFirst a r (cols b) b -- | @align ah av r c bx@ creates an @r@ x @c@ box with the contents -- of @bx@, aligned horizontally according to @ah@ and vertically
Text/PrettyPrint/Tests.hs view
@@ -1,9 +1,16 @@ import Test.QuickCheck import Text.PrettyPrint.Boxes +#if !MIN_VERSION_base(4,8,0)+import Control.Applicative+#endif import Control.Monad import System.Exit (exitFailure, exitSuccess) +#if MIN_VERSION_base(4,11,0)+import Prelude hiding ((<>))+#endif+ instance Arbitrary Alignment where arbitrary = elements [ AlignFirst , AlignCenter1@@ -12,35 +19,53 @@ ] instance Arbitrary Box where- arbitrary = do- (NonNegative r) <- arbitrary- (NonNegative c) <- arbitrary- liftM (Box r c) arbitrary+ arbitrary = sized arbBox +-- A sized generator for boxes. The larger the parameter is, the larger a+-- generated Box is likely to be. This is necessary in order to avoid+-- the tests getting stuck trying to generate ridiculously huge Box values.+arbBox :: Int -> Gen Box+arbBox n =+ Box <$> nonnegative <*> nonnegative <*> arbContent n+ where+ nonnegative = getNonNegative <$> arbitrary+ instance Arbitrary Content where- arbitrary = oneof [ return Blank- , liftM Text arbitrary- , liftM Row arbitrary- , liftM Col arbitrary- , liftM3 SubBox arbitrary arbitrary arbitrary- ]+ arbitrary = sized arbContent +-- A sized generator for Content values. The larger the parameter is, the+-- larger a generated Content is likely to be. This is necessary in order to+-- avoid the tests getting stuck trying to generate ridiculously huge Content+-- values.+--+-- See also section 3.2 of http://www.cs.tufts.edu/%7Enr/cs257/archive/john-hughes/quick.pdf+arbContent :: Int -> Gen Content+arbContent 0 = pure Blank+arbContent n =+ oneof [ pure Blank+ , Text <$> arbitrary+ , Row <$> halveSize (listOf box)+ , Col <$> halveSize (listOf box)+ , SubBox <$> arbitrary <*> arbitrary <*> decrementSize box+ ]+ where+ decrementSize = scale (\s -> max (s - 1) 0)+ halveSize = scale (`quot` 2)+ box = arbBox n+ -- extensional equivalence for Boxes b1 ==== b2 = render b1 == render b2 prop_render_text s = render (text s) == (s ++ "\n") -{--TODO: Find a way to enable these tests without time and space-explosion.----prop_empty_right_id b = b <> nullBox ==== b---prop_empty_left_id b = nullBox <> b ==== b---prop_empty_top_id b = nullBox // b ==== b---prop_empty_bot_id b = b // nullBox ==== b--}+prop_empty_right_id b = b <> nullBox ==== b+prop_empty_left_id b = nullBox <> b ==== b+prop_empty_top_id b = nullBox // b ==== b+prop_empty_bot_id b = b // nullBox ==== b -main = quickCheckResult prop_render_text >>= \result ->- case result of- Success{} -> exitSuccess- _ -> exitFailure+main = do+ quickCheck prop_render_text+ quickCheck prop_empty_right_id+ quickCheck prop_empty_left_id+ quickCheck prop_empty_top_id+ quickCheck prop_empty_bot_id
boxes.cabal view
@@ -1,12 +1,13 @@ name: boxes-version: 0.1.4+version: 0.1.5 synopsis: 2D text pretty-printing library description: A pretty-printing library for laying out text in two dimensions, using a simple box model. category: Text license: BSD3 license-file: LICENSE-extra-source-files: CHANGES, README.md+extra-source-files: CHANGES, README.md, include/boxes.h+ author: Brent Yorgey maintainer: David Feuer <David.Feuer@gmail.com> build-type: Simple@@ -17,19 +18,18 @@ build-depends: base >= 3 && < 5, split >=0.2 && <0.3 exposed-modules: Text.PrettyPrint.Boxes extensions: CPP- if impl(ghc)- extensions: OverloadedStrings+ include-dirs: include Test-Suite test-boxes type: exitcode-stdio-1.0 main-is: Text/PrettyPrint/Tests.hs build-depends: base >= 3 && < 5, split >=0.2 && <0.3, QuickCheck extensions: CPP- if impl(ghc)- extensions: OverloadedStrings+ include-dirs: include cpp-options: -DTESTING+ other-modules: Text.PrettyPrint.Boxes -- Export some internals so the tests can get at them source-repository head type: git- location: git://github.com/treeowl/boxes.git+ location: https://github.com/treeowl/boxes.git
+ include/boxes.h view
@@ -0,0 +1,40 @@+/*+ * Common macros for boxes+ */++#ifndef HASKELL_BOXES_H+#define HASKELL_BOXES_H++#ifdef __GLASGOW_HASKELL__ +#define OVERLOADED_STRINGS 1 +#endif++/*+ * We use cabal-generated MIN_VERSION_base to adapt to changes of base.+ * Nevertheless, as a convenience, we also allow compiling without cabal by+ * defining an approximate MIN_VERSION_base if needed. The alternative version+ * guesses the version of base using the version of GHC. This is usually+ * sufficiently accurate. However, it completely ignores minor version numbers,+ * and it makes the assumption that a pre-release version of GHC will ship with+ * base libraries with the same version numbers as the final release. This+ * assumption is violated in certain stages of GHC development, but in practice+ * this should very rarely matter, and will not affect any released version.+ */+#ifndef MIN_VERSION_base+#if __GLASGOW_HASKELL__ >= 709+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=8)))+#elif __GLASGOW_HASKELL__ >= 707+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=7)))+#elif __GLASGOW_HASKELL__ >= 705+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=6)))+#elif __GLASGOW_HASKELL__ >= 703+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=5)))+#elif __GLASGOW_HASKELL__ >= 701+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=4)))+#elif __GLASGOW_HASKELL__ >= 700+#define MIN_VERSION_base(major1,major2,minor) (((major1)<4)||(((major1) == 4)&&((major2)<=3)))+#else+#define MIN_VERSION_base(major1,major2,minor) (0)+#endif+#endif /* ifndef MIN_VERSION_base */+#endif /* ifndef HASKELL_BOXES_H */