unbeliever 0.8.0.0 → 0.9.2.0
raw patch · 12 files changed
+449/−486 lines, 12 filesdep ~Cabaldep ~aesondep ~asyncPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: Cabal, aeson, async, bytestring, chronologique, containers, deepseq, directory, exceptions, fingertree, gauge, hashable, hourglass, hspec, mtl, prettyprinter, prettyprinter-ansi-terminal, safe-exceptions, scientific, stm, template-haskell, terminal-size, text, text-short, transformers, unix, unordered-containers, vector
API changes (from Hackage documentation)
- Core.Data.Structures: instance Core.Data.Structures.Key ε => Core.Data.Structures.Collection (Data.HashSet.HashSet ε)
- Core.Text.Rope: append :: Textual α => α -> Rope -> Rope
- Core.Text.Rope: contains :: Char -> Rope -> Bool
- Core.Text.Rope: insert :: Int -> Rope -> Rope -> Rope
- Core.Text.Rope: split :: Int -> Rope -> (Rope, Rope)
- Core.Text.Rope: width :: Rope -> Int
- Core.Text.Utilities: instance Core.Text.Utilities.Render [GHC.Types.Char]
+ Core.Data.Structures: instance Core.Data.Structures.Key ε => Core.Data.Structures.Collection (Data.HashSet.Base.HashSet ε)
+ Core.System.Base: data SomeException
+ Core.System.Base: finally :: MonadMask m => m a -> m b -> m a
+ Core.System.Base: impureThrow :: Exception e => e -> a
+ Core.Text.Bytes: instance Core.Text.Bytes.Binary Core.Text.Bytes.Bytes
+ Core.Text.Rope: appendRope :: Textual α => α -> Rope -> Rope
+ Core.Text.Rope: containsCharacter :: Char -> Rope -> Bool
+ Core.Text.Rope: emptyRope :: Rope
+ Core.Text.Rope: insertRope :: Int -> Rope -> Rope -> Rope
+ Core.Text.Rope: splitRope :: Int -> Rope -> (Rope, Rope)
+ Core.Text.Rope: widthRope :: Rope -> Int
+ Core.Text.Utilities: breakLines :: Rope -> [Rope]
+ Core.Text.Utilities: breakPieces :: (Char -> Bool) -> Rope -> [Rope]
+ Core.Text.Utilities: breakWords :: Rope -> [Rope]
+ Core.Text.Utilities: instance Core.Text.Utilities.Render GHC.Types.Char
+ Core.Text.Utilities: instance Core.Text.Utilities.Render a => Core.Text.Utilities.Render [a]
- Core.Program.Execute: terminate :: Int -> Program τ ()
+ Core.Program.Execute: terminate :: Int -> Program τ α
Files
- LICENCE +1/−1
- lib/Core/Program/Execute.hs +1/−4
- lib/Core/Program/Logging.hs +1/−1
- lib/Core/System/Base.hs +5/−1
- lib/Core/Text/Bytes.hs +4/−0
- lib/Core/Text/Rope.hs +56/−41
- lib/Core/Text/Utilities.hs +136/−17
- tests/CheckRopeBehaviour.hs +87/−26
- tests/SimpleExperiment.hs +0/−111
- tests/Snippet.hs +0/−31
- tests/TestSuite.hs +2/−2
- unbeliever.cabal +156/−251
LICENCE view
@@ -1,6 +1,6 @@ Opinionated Haskell Interoperability -Copyright © 2018 Operational Dynamics Consulting, Pty Ltd and Others+Copyright © 2018-2019 Operational Dynamics Consulting, Pty Ltd and Others All rights reserved. Redistribution and use in source and binary forms, with or without
lib/Core/Program/Execute.hs view
@@ -1,9 +1,6 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE StrictData #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE BangPatterns #-}@@ -272,7 +269,7 @@ -- putting to the quit MVar initiates the cleanup and exit sequence, -- but throwing the exception also aborts execution and starts unwinding -- back up the stack.-terminate :: Int -> Program τ ()+terminate :: Int -> Program τ α terminate code = let exit = case code of
lib/Core/Program/Logging.hs view
@@ -160,7 +160,7 @@ let display = case potentialValue of Just value ->- if contains '\n' value+ if containsCharacter '\n' value then text <> " =\n" <> value else text <> " = " <> value Nothing -> text
lib/Core/System/Base.hs view
@@ -21,12 +21,16 @@ {-** from Control.Exception.Safe -} {-| Re-exported from "Control.Exception.Safe" in the __safe-exceptions__ package: -} , Exception(..)+ , SomeException , throw+ , impureThrow , bracket , catch+ , finally ) where -import Control.Exception.Safe (Exception(..), throw, bracket, catch)+import Control.Exception.Safe (Exception(..), SomeException, throw+ , bracket, catch, finally, impureThrow) import Control.Monad.IO.Class (MonadIO, liftIO) import System.IO (Handle, stdin, stdout, stderr, hFlush) import System.IO.Unsafe (unsafePerformIO)
lib/Core/Text/Bytes.hs view
@@ -74,6 +74,10 @@ fromBytes :: Bytes -> α intoBytes :: α -> Bytes +instance Binary Bytes where+ fromBytes = id+ intoBytes = id+ {-| from "Data.ByteString" Strict -} instance Binary B.ByteString where fromBytes (StrictBytes b') = b'
lib/Core/Text/Rope.hs view
@@ -74,12 +74,13 @@ module Core.Text.Rope ( {-* Rope type -} Rope- , width- , split- , insert- , contains+ , emptyRope+ , widthRope+ , splitRope+ , insertRope+ , containsCharacter {-* Interoperation and Output -}- , Textual(fromRope, intoRope, append)+ , Textual(fromRope, intoRope, appendRope) , hWrite {-* Internals -} , unRope@@ -93,10 +94,11 @@ , hPutBuilder) import qualified Data.ByteString.Lazy as L (ByteString, toStrict , foldrChunks)-import Data.String (IsString(..)) import qualified Data.FingerTree as F (FingerTree, Measured(..), empty- , singleton, (><), (<|), (|>), search, SearchResult(..))+ , singleton, (><), (<|), (|>), search, SearchResult(..), null) import Data.Foldable (foldr, foldr', foldMap, toList, any)+import Data.Hashable (Hashable, hashWithSalt)+import Data.String (IsString(..)) import qualified Data.Text as T (Text) import qualified Data.Text.Lazy as U (Text, fromChunks, foldrChunks , toStrict)@@ -107,7 +109,6 @@ , fromText, toText, fromByteString, pack, unpack , append, empty, toBuilder, splitAt) import qualified Data.Text.Short.Unsafe as S (fromByteStringUnsafe)-import Data.Hashable (Hashable, hashWithSalt) import GHC.Generics (Generic) import System.IO (Handle) @@ -141,8 +142,8 @@ This involves considerable appending of data, very very occaisionally inserting it. Often the pieces are tiny. To add text to a @Rope@ use the-'append' method as below or ('Data.Semigroup.<>') from "Data.Monoid" (like you-would have with a @Builder@).+'appendRope' method as below or the ('Data.Semigroup.<>') operator from+"Data.Monoid" (like you would have with a @Builder@). Output to a @Handle@ can be done efficiently with 'hWrite'. -}@@ -203,20 +204,35 @@ -- FingerTree Strand or Builder (Strand) instance IsString Rope where- fromString = Rope . F.singleton . S.pack+ fromString "" = emptyRope+ fromString xs = Rope . F.singleton . S.pack $ xs instance Semigroup Rope where- (<>) (Rope x1) (Rope x2) = Rope ((F.><) x1 x2) -- god I hate these operators+ (<>) text1@(Rope x1) text2@(Rope x2) =+ if F.null x2+ then text1+ else if F.null x1+ then text2+ else Rope ((F.><) x1 x2) -- god I hate these operators instance Monoid Rope where- mempty = Rope F.empty+ mempty = emptyRope mappend = (<>) {-|+An zero-length 'Rope'. You can also use @\"\"@ presuming the+__@OverloadedStrings@__ language extension is turned on in your source+file.+-}+emptyRope :: Rope+emptyRope = Rope F.empty+{-# INLINABLE emptyRope #-}++{-| Get the length of this text, in characters. -}-width :: Rope -> Int-width = foldr' f 0 . unRope+widthRope :: Rope -> Int+widthRope = foldr' f 0 . unRope where f piece count = S.length piece + count @@ -226,25 +242,25 @@ Examples: @-λ> __split 0 \"abcdef\"__+λ> __splitRope 0 \"abcdef\"__ (\"\", \"abcdef\")-λ> __split 3 \"abcdef\"__+λ> __splitRope 3 \"abcdef\"__ (\"abc\", \"def\")-λ> __split 6 \"abcdef\"__+λ> __splitRope 6 \"abcdef\"__ (\"abcdef\",\"\") @ Going off either end behaves sensibly: @-λ> __split 7 \"abcdef\"__+λ> __splitRope 7 \"abcdef\"__ (\"abcdef\",\"\")-λ> __split (-1) \"abcdef\"__+λ> __splitRope (-1) \"abcdef\"__ (\"\", \"abcdef\") @ -}-split :: Int -> Rope -> (Rope,Rope)-split i text@(Rope x) =+splitRope :: Int -> Rope -> (Rope,Rope)+splitRope i text@(Rope x) = let pos = Width i result = F.search (\w1 _ -> w1 >= pos) x@@ -266,21 +282,20 @@ Examples: @-λ> __insert 3 \"Con\" \"Def 1\"__+λ> __insertRope 3 \"Con\" \"Def 1\"__ "DefCon 1"-λ> __insert 0 \"United \" \"Nations\"__+λ> __insertRope 0 \"United \" \"Nations\"__ "United Nations" @ -}-insert :: Int -> Rope -> Rope -> Rope-insert 0 (Rope new) (Rope x) = Rope ((F.><) new x)-insert i (Rope new) text =+insertRope :: Int -> Rope -> Rope -> Rope+insertRope 0 (Rope new) (Rope x) = Rope ((F.><) new x)+insertRope i (Rope new) text = let- (Rope before,Rope after) = split i text+ (Rope before,Rope after) = splitRope i text in Rope (mconcat [before, new, after]) - -- -- Manual instance to get around the fact that FingerTree doesn't have a -- Hashable instance. If this were ever to become a hotspot we could@@ -311,11 +326,11 @@ collector manage the memory, so instances are expected to /copy/ these substrings out of pinned memory. -The @ByteString@ instance requires that its content be valid UTF-8. If not an-empty @Rope@ will be returned.+The @ByteString@ instance requires that its content be valid UTF-8. If not+an empty @Rope@ will be returned. Several of the 'fromRope' implementations are expensive and involve a lot-of intermiate allocation and copying. If you're ultimately writing to a+of intermediate allocation and copying. If you're ultimately writing to a handle prefer 'hWrite' which will write directly to the output buffer. -} class Textual α where@@ -333,8 +348,8 @@ text (which will work just fine, but for some types more efficient implementations are possible). -}- append :: α -> Rope -> Rope- append thing text = text <> intoRope thing+ appendRope :: α -> Rope -> Rope+ appendRope thing text = text <> intoRope thing instance Textual (F.FingerTree Width S.ShortText) where fromRope = unRope@@ -343,13 +358,13 @@ instance Textual Rope where fromRope = id intoRope = id- append (Rope x2) (Rope x1) = Rope ((F.><) x1 x2)+ appendRope (Rope x2) (Rope x1) = Rope ((F.><) x1 x2) {-| from "Data.Text.Short" -} instance Textual S.ShortText where fromRope = foldr S.append S.empty . unRope intoRope = Rope . F.singleton- append piece (Rope x) = Rope ((F.|>) x piece)+ appendRope piece (Rope x) = Rope ((F.|>) x piece) {-| from "Data.Text" Strict -} instance Textual T.Text where@@ -359,7 +374,7 @@ f piece built = (<>) (U.fromText (S.toText piece)) built intoRope t = Rope (F.singleton (S.fromText t))- append chunk (Rope x) = Rope ((F.|>) x (S.fromText chunk))+ appendRope chunk (Rope x) = Rope ((F.|>) x (S.fromText chunk)) {-| from "Data.Text.Lazy" -} instance Textual U.Text where@@ -379,7 +394,7 @@ Nothing -> Rope F.empty -- bad -- ditto- append b' (Rope x) = case S.fromByteString b' of+ appendRope b' (Rope x) = case S.fromByteString b' of Just piece -> Rope ((F.|>) x piece) Nothing -> (Rope x) -- bad @@ -449,12 +464,12 @@ example: @- if 'contains' '\n' text+ if 'containsCharacter' \'\n\' text then handleComplexCase else keepItSimple @ -}-contains :: Char -> Rope -> Bool-contains q (Rope x) = any j x+containsCharacter :: Char -> Rope -> Bool+containsCharacter q (Rope x) = any j x where j piece = S.any (\c -> c == q) piece
lib/Core/Text/Utilities.hs view
@@ -16,18 +16,22 @@ , render {-* Helpers -} , indefinite+ , breakWords+ , breakLines+ , breakPieces , wrap , underline {-* Multi-line strings -} , quote ) where -import qualified Data.FingerTree as F ((<|), ViewL(..), viewl)+import Data.Char (isSpace)+import qualified Data.FingerTree as F ((<|), ViewL(..), viewl, singleton) import qualified Data.List as List (foldl', dropWhileEnd) import Data.Monoid ((<>)) import qualified Data.Text as T-import qualified Data.Text.Lazy.Builder as T-import qualified Data.Text.Short as S (ShortText, uncons, toText)+import qualified Data.Text.Short as S (ShortText, uncons, toText, empty+ , null, breakEnd, append, dropEnd) import Data.Text.Prettyprint.Doc (Doc, layoutPretty , reAnnotateS , pretty, emptyDoc , LayoutOptions(LayoutOptions)@@ -73,11 +77,16 @@ f :: S.ShortText -> Doc () -> Doc () f piece built = (<>) (pretty (S.toText piece)) built -instance Render [Char] where- type Token [Char] = ()+instance Render Char where+ type Token Char = () colourize = const mempty- intoDocA cs = pretty cs+ intoDocA c = pretty c +instance (Render a) => Render [a] where+ type Token [a] = Token a+ colourize = const mempty+ intoDocA = mconcat . fmap intoDocA+ instance Render T.Text where type Token T.Text = () colourize = const mempty@@ -134,33 +143,143 @@ else intoRope ("a " F.<| x) {-|+Split a passage of text into a list of words. A line is broken wherever+there is one or more whitespace characters, as defined by "Data.Char"'s+'Data.Char.isSpace'.++Examples:++@+λ> __breakWords \"This is a test\"__+[\"This\",\"is\",\"a\",\"test\"]+λ> __breakWords (\"St\" <> \"op and \" <> \"go left\")__+[\"Stop\",\"and\",\"go\",\"left\"]+λ> __breakWords emptyRope__+[]+@+-}+breakWords :: Rope -> [Rope]+breakWords text = breakPieces isSpace text++{-|+Split a paragraph of text into a list of its individual lines. The+paragraph will be broken wherever there is a @'\n'@ character.+-}+breakLines :: Rope -> [Rope]+breakLines text = breakPieces isNewline text++isNewline :: Char -> Bool+isNewline c = c == '\n'++{-|+Break a Rope into pieces whereever the given predicate function returns+@True@. If found, that character will not be included on either side.+-}+breakPieces :: (Char -> Bool) -> Rope -> [Rope]+breakPieces predicate text =+ let+ (final,list) = foldr (finder predicate) (S.empty,[]) (unRope text)+ l = intoRope (F.singleton final)+ in+ if S.null final+ then list+ else l:list++finder+ :: (Char -> Bool)+ -> S.ShortText+ -> (S.ShortText,[Rope])+ -> (S.ShortText,[Rope])+finder predicate piece (accum,list) =+ let+ done = S.null piece++ -- λ> S.breakEnd isSpace "a d"+ -- ("a","d")+ --+ -- λ> S.breakEnd isSpace " and"+ -- (" ","and")+ --+ -- λ> S.breakEnd isSpace "and "+ -- ("and ","")+ --+ -- λ> S.breakEnd isSpace ""+ -- ("","")+ --+ -- λ> S.breakEnd isSpace " "+ -- (" ","")++ (remainder,fragment) = S.breakEnd predicate piece++ -- Are we in the middle of a word? We are if the carry forward is+ -- non-zero length.+ --+ -- Did we find a word in the current piece? If so, then if we are in+ -- the middle of accumulating a word, we add the new piece to it.++ found = not (S.null fragment)+ middle = not (S.null accum)++ accum' = if found+ then if middle+ then S.append fragment accum+ else fragment+ else accum++ -- Did we find a space? We did if remainder is non-zero length.+ -- Finding a space means flushing out the accumulator (though only if+ -- there's actually something there). We have to drop that whitespace+ -- before iterating.++ space = not (S.null remainder)+ empty = S.null accum'+ word = intoRope accum'++ list' = if empty+ then list+ else word:list++ remainder' = S.dropEnd 1 remainder+ in+ if done+ then (accum',list)+ else if space+ then finder predicate remainder' (S.empty,list')+ else finder predicate remainder (accum',list)++{-| Often the input text represents a paragraph, but does not have any internal newlines (representing word wrapping). This function takes a line of text-and inserts newlines to simulate such folding. It also appends a trailing-newline to finish the paragraph.+and inserts newlines to simulate such folding, keeping the line under+the supplied maximum width.++A single word that is excessively long will be included as-is on its own+line (that line will exceed the desired maxium width).++Any trailing newlines will be removed. -} wrap :: Int -> Rope -> Rope wrap margin text = let- built = wrapHelper margin (T.words (fromRope text))+ built = wrapHelper margin (breakWords text) in- intoRope (T.toLazyText built)+ built -wrapHelper :: Int -> [T.Text] -> T.Builder+wrapHelper :: Int -> [Rope] -> Rope wrapHelper _ [] = ""-wrapHelper _ [x] = T.fromText x+wrapHelper _ [x] = x wrapHelper margin (x:xs) =- snd $ List.foldl' (wrapLine margin) (T.length x, T.fromText x) xs+ snd $ List.foldl' (wrapLine margin) (widthRope x, x) xs -wrapLine :: Int -> (Int, T.Builder) -> T.Text -> (Int, T.Builder)+wrapLine :: Int -> (Int, Rope) -> Rope -> (Int, Rope) wrapLine margin (pos,builder) word = let- wide = T.length word+ wide = widthRope word wide' = pos + wide + 1 in if wide' > margin- then (wide , builder <> "\n" <> T.fromText word)- else (wide', builder <> " " <> T.fromText word)+ then (wide , builder <> "\n" <> word)+ else (wide', builder <> " " <> word) underline :: Char -> Rope -> Rope
tests/CheckRopeBehaviour.hs view
@@ -30,9 +30,9 @@ unRope ("Hello" :: Rope) `shouldBe` F.singleton (S.pack "Hello") it "calculates length accurately" $ do- width hydrogen `shouldBe` 2- width sulfate `shouldBe` 3- width (hydrogen <> sulfate) `shouldBe` 5+ widthRope hydrogen `shouldBe` 2+ widthRope sulfate `shouldBe` 3+ widthRope (hydrogen <> sulfate) `shouldBe` 5 it "Eq instance behaves" $ do ("" :: Rope) == ("" :: Rope) `shouldBe` True@@ -48,7 +48,7 @@ ("H₂" :: Rope) <> ("SO₄" :: Rope) `shouldBe` ("H₂SO₄" :: Rope) it "concatonates two Ropes correctly (Textual)" $ do- append ("SO₄" :: Rope) ("H₂" :: Rope) `shouldBe` ("H₂SO₄" :: Rope)+ appendRope ("SO₄" :: Rope) ("H₂" :: Rope) `shouldBe` ("H₂SO₄" :: Rope) it "exports to ByteString" $ let@@ -68,32 +68,32 @@ List.splitAt 3 ("123456789" :: String) `shouldBe` ("123", "456789") -- expect same behaviour of Rope- split 0 ("123456789" :: Rope) `shouldBe` ("", "123456789")- split 3 ("123456789" :: Rope) `shouldBe` ("123", "456789")- split 9 ("123456789" :: Rope) `shouldBe` ("123456789","")- split 10 ("123456789" :: Rope) `shouldBe` ("123456789","")- split (-1) ("123456789" :: Rope) `shouldBe` ("", "123456789")+ splitRope 0 ("123456789" :: Rope) `shouldBe` ("", "123456789")+ splitRope 3 ("123456789" :: Rope) `shouldBe` ("123", "456789")+ splitRope 9 ("123456789" :: Rope) `shouldBe` ("123456789","")+ splitRope 10 ("123456789" :: Rope) `shouldBe` ("123456789","")+ splitRope (-1) ("123456789" :: Rope) `shouldBe` ("", "123456789") - -- exercise splitting at and between piece boundaries- split 0 compound `shouldBe` ("", "3-ethyl-4-methylhexane")- split 1 compound `shouldBe` ("3", "-ethyl-4-methylhexane")- split 2 compound `shouldBe` ("3-", "ethyl-4-methylhexane")- split 4 compound `shouldBe` ("3-et", "hyl-4-methylhexane")+ -- exercise splitRopeting at and between piece boundaries+ splitRope 0 compound `shouldBe` ("", "3-ethyl-4-methylhexane")+ splitRope 1 compound `shouldBe` ("3", "-ethyl-4-methylhexane")+ splitRope 2 compound `shouldBe` ("3-", "ethyl-4-methylhexane")+ splitRope 4 compound `shouldBe` ("3-et", "hyl-4-methylhexane") -- 1234567890- split 10 compound `shouldBe` ("3-ethyl-4-", "methylhexane")- split 11 compound `shouldBe` ("3-ethyl-4-m", "ethylhexane")- split 16 compound `shouldBe` ("3-ethyl-4-methyl", "hexane")- split 21 compound `shouldBe` ("3-ethyl-4-methylhexan", "e")- width compound `shouldBe` 22- split 22 compound `shouldBe` ("3-ethyl-4-methylhexane", "")- split 23 compound `shouldBe` ("3-ethyl-4-methylhexane", "")- split (-1) compound `shouldBe` ("", "3-ethyl-4-methylhexane")+ splitRope 10 compound `shouldBe` ("3-ethyl-4-", "methylhexane")+ splitRope 11 compound `shouldBe` ("3-ethyl-4-m", "ethylhexane")+ splitRope 16 compound `shouldBe` ("3-ethyl-4-methyl", "hexane")+ splitRope 21 compound `shouldBe` ("3-ethyl-4-methylhexan", "e")+ widthRope compound `shouldBe` 22+ splitRope 22 compound `shouldBe` ("3-ethyl-4-methylhexane", "")+ splitRope 23 compound `shouldBe` ("3-ethyl-4-methylhexane", "")+ splitRope (-1) compound `shouldBe` ("", "3-ethyl-4-methylhexane") it "does insertion correctly" $ do- insert 3 "two" "onethree" `shouldBe` "onetwothree"- insert 3 "Con" "Def 1" `shouldBe` "DefCon 1"- insert 0 "one" "twothree" `shouldBe` "onetwothree"- insert 6 "three" "onetwo" `shouldBe` "onetwothree"+ insertRope 3 "two" "onethree" `shouldBe` "onetwothree"+ insertRope 3 "Con" "Def 1" `shouldBe` "DefCon 1"+ insertRope 0 "one" "twothree" `shouldBe` "onetwothree"+ insertRope 6 "three" "onetwo" `shouldBe` "onetwothree" describe "QuasiQuoted string literals" $ do@@ -110,3 +110,64 @@ World |] `shouldBe` ("Hello\nWorld\n" :: Rope) + describe "Splitting into words" $ do+ it "single piece containing multiple words splits correctly" $+ let+ text = "This is a test"+ in do+ breakWords text `shouldBe` ["This","is","a","test"]++ it "single piece, long run of whitespace splits correctly" $+ let+ text = "This is\na test"+ in do+ breakWords text `shouldBe` ["This","is","a","test"]++ it "text spanning two pieces can be split into words" $+ let+ text = "This is " <> "a test"+ in do+ breakWords text `shouldBe` ["This","is","a","test"]++ it "text spanning many pieces can be split into words" $+ let+ text = "st" <> "" <> "op" <> "" <> " " <> " " <> "and go" <> "op"+ in do+ breakWords text `shouldBe` ["stop","and","goop"]++ it "empty and whitespace-only corner cases handled correctly " $+ let+ text = " " <> "" <> "stop" <> "" <> " "+ in do+ breakWords text `shouldBe` ["stop"]++ describe "Splitting into lines" $ do+ it "single piece containing multiple lines splits correctly" $+ let+ para = [quote|+This is a test+of the Emergency+Broadcast+System, beeeeep+|]+ in do+ breakLines para `shouldBe`+ [ "This is a test"+ , "of the Emergency"+ , "Broadcast"+ , "System, beeeeep"+ ]++ describe "Formatting paragraphs" $ do+ it "multi-line paragraph rewraps correctly" $+ let+ para = [quote|+Hello this is+a test+ of the Emergency Broadcast System+ |]+ in+ wrap 20 para `shouldBe` [quote|+Hello this is a test+of the Emergency+Broadcast System|]
− tests/SimpleExperiment.hs
@@ -1,111 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE OverloadedLists #-}-{-# LANGUAGE QuasiQuotes #-}-{-# LANGUAGE TemplateHaskell #-}-{-# OPTIONS_GHC -fno-warn-unused-imports #-}-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}-{-# OPTIONS_GHC -fno-warn-missing-signatures #-}-{-# OPTIONS_GHC -fno-warn-name-shadowing #-}-{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}----import Data.Text (Text)-import Control.Concurrent (threadDelay)-import Control.Monad (replicateM_)-import qualified Data.ByteString.Char8 as S-import qualified Data.HashMap.Strict as HashMap-import Data.Text.Prettyprint.Doc (layoutPretty, defaultLayoutOptions, Pretty(..))-import Data.Text.Prettyprint.Doc.Render.Text (renderStrict)--import Core.Data-import Core.Text-import Core.Encoding-import Core.Program-import Core.System--k = JsonKey "intro"-v = JsonString "Hello"--j = JsonObject- [ (k, v)- , (JsonKey "song", JsonString "Thriller")- , ("other", "A very long name for the \"shadow of the moon\".")- , (JsonKey "four", JsonObject- [ (JsonKey "n1", r)- ])- ]--b = intoBytes (S.pack "{\"cost\": 4500}")--r = JsonArray [JsonBool False, JsonNull, 42]--data Boom = Boom- deriving Show--instance Exception Boom--program :: Program None ()-program = do- event "Starting..."-- params <- getCommandLine- debugS "params" params-- level <- getVerbosityLevel- debugS "level" level-- name <- getProgramName- debug "programName" name-- setProgramName "hello"-- name <- getProgramName- debug "programName" name-- debugR "key" k- event "Verify internal values"-- state <- getApplicationState- debugS "state" state-- let x = encodeToUTF8 j- writeS x-- let (Just y) = decodeFromUTF8 b- writeS y- writeS (encodeToUTF8 y)- writeR (encodeToUTF8 y)- writeS (encodeToUTF8 r)-- debugR "packet" j-- event "Clock..."-- fork $ do- sleep 1.5- event "Wakey wakey"- throw Boom-- replicateM_ 5 $ do- sleep 0.5- event "tick"--- event "Brr! It's cold"- terminate 0--version :: Version-version = $(fromPackage)--main :: IO ()-main = do- context <- configure version None (simple- [ Option "quiet" (Just 'q') Empty [quote|- Supress normal output.- |]- , Argument "filename" [quote|- The file you want to frobnicate.- |]- , Variable "HOME" "Home directory"- ])-- executeWith context program
− tests/Snippet.hs
@@ -1,31 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE QuasiQuotes #-}-{-# OPTIONS_GHC -fno-warn-unused-imports #-}-{-# OPTIONS_GHC -fno-warn-unused-top-binds #-}-{-# OPTIONS_GHC -fno-warn-missing-signatures #-}-{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}--import qualified Data.ByteString.Char8 as C--import Core.Program-import Core.Text-import Core.System--b = intoBytes (C.pack "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789")--data Boom = Boom deriving Show-instance Exception Boom--main :: IO ()-main = execute $ do- event "Processing..."- debugR "b" b-- let x = error "No!"-- write $ case x of- Nothing -> "Nothing!"-- sleep 0.2-- write "Done"
tests/TestSuite.hs view
@@ -2,6 +2,7 @@ import Test.Hspec +import Core.System import CheckRopeBehaviour import CheckBytesBehaviour import CheckContainerBehaviour@@ -11,8 +12,7 @@ main :: IO () main = do- hspec suite- putStrLn "."+ finally (hspec suite) (putStrLn ".") suite :: Spec suite = do
unbeliever.cabal view
@@ -1,260 +1,165 @@ cabal-version: 1.12---- This file has been generated from package.yaml by hpack version 0.31.1.------ see: https://github.com/sol/hpack------ hash: dc4af83e0e28d0d48d8e6550b7def407de3c5e3cc34d5c6380ecbfdc74229985--name: unbeliever-version: 0.8.0.0-synopsis: Opinionated Haskell Interoperability-description: A library to help build command-line programs, both tools and- longer-running daemons.- .- A description of this package, a list of features, and some background- to its design is contained in the- <https://github.com/oprdyn/unbeliever/blob/master/README.markdown README>- on GitHub.- .- Useful starting points in the documentation are "Core.Program.Execute"- and "Core.Text.Rope".-category: System-stability: experimental-homepage: https://github.com/oprdyn/unbeliever#readme-bug-reports: https://github.com/oprdyn/unbeliever/issues-author: Andrew Cowie <andrew@operationaldynamics.com>-maintainer: Andrew Cowie <andrew@operationaldynamics.com>-copyright: © 2018 Operational Dynamics Consulting Pty Ltd, and Others-license: BSD3-license-file: LICENCE-tested-with: GHC == 8.4-build-type: Simple+name: unbeliever+version: 0.9.2.0+license: BSD3+license-file: LICENCE+copyright: © 2018-2019 Operational Dynamics Consulting Pty Ltd, and Others+maintainer: Andrew Cowie <andrew@operationaldynamics.com>+author: Andrew Cowie <andrew@operationaldynamics.com>+stability: experimental+tested-with: ghc ==8.6.4+homepage: https://github.com/oprdyn/unbeliever#readme+bug-reports: https://github.com/oprdyn/unbeliever/issues+synopsis: Opinionated Haskell Interoperability+description:+ A library to help build command-line programs, both tools and+ longer-running daemons.+ .+ A description of this package, a list of features, and some background+ to its design is contained in the+ <https://github.com/oprdyn/unbeliever/blob/master/README.markdown README>+ on GitHub.+ .+ Useful starting points in the documentation are "Core.Program.Execute"+ and "Core.Text.Rope".+category: System+build-type: Simple source-repository head- type: git- location: https://github.com/oprdyn/unbeliever--flag development- manual: True- default: False+ type: git+ location: https://github.com/oprdyn/unbeliever library- exposed-modules:- Core.Data- Core.Data.Structures- Core.Encoding- Core.Encoding.Json- Core.Program- Core.Program.Arguments- Core.Program.Execute- Core.Program.Logging- Core.Program.Metadata- Core.Program.Unlift- Core.Text- Core.Text.Bytes- Core.Text.Rope- Core.Text.Utilities- Core.System- Core.System.Base- Core.System.External- other-modules:- Core.Program.Context- Core.Program.Signal- hs-source-dirs:- lib- ghc-options: -Wall -Wwarn -fwarn-tabs- build-depends:- Cabal- , aeson- , async- , base >=4.11 && <5- , bytestring- , chronologique- , containers- , deepseq- , directory- , exceptions- , fingertree- , hashable- , hourglass- , mtl- , prettyprinter- , prettyprinter-ansi-terminal- , safe-exceptions- , scientific- , stm- , template-haskell- , terminal-size- , text- , text-short- , transformers- , unix- , unordered-containers- , vector- default-language: Haskell2010--executable experiment- main-is: SimpleExperiment.hs- hs-source-dirs:- tests- ghc-options: -Wall -Wwarn -fwarn-tabs -threaded- build-depends:- Cabal- , aeson- , async- , base >=4.11 && <5- , bytestring- , chronologique- , containers- , deepseq- , directory- , exceptions- , fingertree- , hashable- , hourglass- , mtl- , prettyprinter- , prettyprinter-ansi-terminal- , safe-exceptions- , scientific- , stm- , template-haskell- , terminal-size- , text- , text-short- , transformers- , unbeliever- , unix- , unordered-containers- , vector- if flag(development)- ghc-prof-options: -fprof-auto-top- buildable: True- else- buildable: False- default-language: Haskell2010--executable snippet- main-is: Snippet.hs- hs-source-dirs:- tests- ghc-options: -Wall -Wwarn -fwarn-tabs -threaded- build-depends:- Cabal- , aeson- , async- , base >=4.11 && <5- , bytestring- , chronologique- , containers- , deepseq- , directory- , exceptions- , fingertree- , hashable- , hourglass- , mtl- , prettyprinter- , prettyprinter-ansi-terminal- , safe-exceptions- , scientific- , stm- , template-haskell- , terminal-size- , text- , text-short- , transformers- , unbeliever- , unix- , unordered-containers- , vector- if flag(development)- ghc-prof-options: -fprof-auto-top- buildable: True- else- buildable: False- default-language: Haskell2010+ exposed-modules:+ Core.Data+ Core.Data.Structures+ Core.Encoding+ Core.Encoding.Json+ Core.Program+ Core.Program.Arguments+ Core.Program.Execute+ Core.Program.Logging+ Core.Program.Metadata+ Core.Program.Unlift+ Core.Text+ Core.Text.Bytes+ Core.Text.Rope+ Core.Text.Utilities+ Core.System+ Core.System.Base+ Core.System.External+ hs-source-dirs: lib+ other-modules:+ Core.Program.Context+ Core.Program.Signal+ default-language: Haskell2010+ ghc-options: -Wall -Wwarn -fwarn-tabs+ build-depends:+ Cabal >=2.4.1.0 && <2.5,+ aeson >=1.4.2.0 && <1.5,+ async >=2.2.1 && <2.3,+ base >=4.11 && <5,+ bytestring >=0.10.8.2 && <0.11,+ chronologique >=0.3.1.1 && <0.4,+ containers >=0.6.0.1 && <0.7,+ deepseq >=1.4.4.0 && <1.5,+ directory >=1.3.3.0 && <1.4,+ exceptions >=0.10.0 && <0.11,+ fingertree >=0.1.4.2 && <0.2,+ hashable >=1.2.7.0 && <1.3,+ hourglass >=0.2.12 && <0.3,+ mtl >=2.2.2 && <2.3,+ prettyprinter >=1.2.1 && <1.3,+ prettyprinter-ansi-terminal >=1.1.1.2 && <1.2,+ safe-exceptions >=0.1.7.0 && <0.2,+ scientific >=0.3.6.2 && <0.4,+ stm >=2.5.0.0 && <2.6,+ template-haskell >=2.14.0.0 && <2.15,+ terminal-size >=0.3.2.1 && <0.4,+ text >=1.2.3.1 && <1.3,+ text-short >=0.1.2 && <0.2,+ transformers >=0.5.6.2 && <0.6,+ unix >=2.7.2.2 && <2.8,+ unordered-containers >=0.2.9.0 && <0.3,+ vector >=0.12.0.2 && <0.13 test-suite check- type: exitcode-stdio-1.0- main-is: TestSuite.hs- other-modules:- CheckArgumentsParsing- CheckBytesBehaviour- CheckContainerBehaviour- CheckJsonWrapper- CheckProgramMonad- CheckRopeBehaviour- hs-source-dirs:- tests- ghc-options: -Wall -Wwarn -fwarn-tabs -threaded- build-depends:- Cabal- , aeson- , async- , base >=4.11 && <5- , bytestring- , chronologique- , containers- , deepseq- , directory- , exceptions- , fingertree- , hashable- , hourglass- , hspec- , mtl- , prettyprinter- , prettyprinter-ansi-terminal- , safe-exceptions- , scientific- , stm- , template-haskell- , terminal-size- , text- , text-short- , transformers- , unbeliever- , unix- , unordered-containers- , vector- default-language: Haskell2010+ type: exitcode-stdio-1.0+ main-is: TestSuite.hs+ hs-source-dirs: tests+ other-modules:+ CheckArgumentsParsing+ CheckBytesBehaviour+ CheckContainerBehaviour+ CheckJsonWrapper+ CheckProgramMonad+ CheckRopeBehaviour+ default-language: Haskell2010+ ghc-options: -Wall -Wwarn -fwarn-tabs -threaded+ build-depends:+ Cabal >=2.4.1.0 && <2.5,+ aeson >=1.4.2.0 && <1.5,+ async >=2.2.1 && <2.3,+ base >=4.11 && <5,+ bytestring >=0.10.8.2 && <0.11,+ chronologique >=0.3.1.1 && <0.4,+ containers >=0.6.0.1 && <0.7,+ deepseq >=1.4.4.0 && <1.5,+ directory >=1.3.3.0 && <1.4,+ exceptions >=0.10.0 && <0.11,+ fingertree >=0.1.4.2 && <0.2,+ hashable >=1.2.7.0 && <1.3,+ hourglass >=0.2.12 && <0.3,+ hspec >=2.6.1 && <2.7,+ mtl >=2.2.2 && <2.3,+ prettyprinter >=1.2.1 && <1.3,+ prettyprinter-ansi-terminal >=1.1.1.2 && <1.2,+ safe-exceptions >=0.1.7.0 && <0.2,+ scientific >=0.3.6.2 && <0.4,+ stm >=2.5.0.0 && <2.6,+ template-haskell >=2.14.0.0 && <2.15,+ terminal-size >=0.3.2.1 && <0.4,+ text >=1.2.3.1 && <1.3,+ text-short >=0.1.2 && <0.2,+ transformers >=0.5.6.2 && <0.6,+ unbeliever -any,+ unix >=2.7.2.2 && <2.8,+ unordered-containers >=0.2.9.0 && <0.3,+ vector >=0.12.0.2 && <0.13 benchmark performance- type: exitcode-stdio-1.0- main-is: GeneralPerformance.hs- hs-source-dirs:- bench- ghc-options: -Wall -Wwarn -fwarn-tabs -threaded- build-depends:- Cabal- , aeson- , async- , base >=4.11 && <5- , bytestring- , chronologique- , containers- , deepseq- , directory- , exceptions- , fingertree- , gauge- , hashable- , hourglass- , mtl- , prettyprinter- , prettyprinter-ansi-terminal- , safe-exceptions- , scientific- , stm- , template-haskell- , terminal-size- , text- , text-short- , transformers- , unbeliever- , unix- , unordered-containers- , vector- default-language: Haskell2010+ type: exitcode-stdio-1.0+ main-is: GeneralPerformance.hs+ hs-source-dirs: bench+ default-language: Haskell2010+ ghc-options: -Wall -Wwarn -fwarn-tabs -threaded+ build-depends:+ Cabal >=2.4.1.0 && <2.5,+ aeson >=1.4.2.0 && <1.5,+ async >=2.2.1 && <2.3,+ base >=4.11 && <5,+ bytestring >=0.10.8.2 && <0.11,+ chronologique >=0.3.1.1 && <0.4,+ containers >=0.6.0.1 && <0.7,+ deepseq >=1.4.4.0 && <1.5,+ directory >=1.3.3.0 && <1.4,+ exceptions >=0.10.0 && <0.11,+ fingertree >=0.1.4.2 && <0.2,+ gauge >=0.2.4 && <0.3,+ hashable >=1.2.7.0 && <1.3,+ hourglass >=0.2.12 && <0.3,+ mtl >=2.2.2 && <2.3,+ prettyprinter >=1.2.1 && <1.3,+ prettyprinter-ansi-terminal >=1.1.1.2 && <1.2,+ safe-exceptions >=0.1.7.0 && <0.2,+ scientific >=0.3.6.2 && <0.4,+ stm >=2.5.0.0 && <2.6,+ template-haskell >=2.14.0.0 && <2.15,+ terminal-size >=0.3.2.1 && <0.4,+ text >=1.2.3.1 && <1.3,+ text-short >=0.1.2 && <0.2,+ transformers >=0.5.6.2 && <0.6,+ unbeliever -any,+ unix >=2.7.2.2 && <2.8,+ unordered-containers >=0.2.9.0 && <0.3,+ vector >=0.12.0.2 && <0.13