{-# LANGUAGE TypeSynonymInstances #-} -- | When the output of a command is long, keeping it as a `String` is a bad idea. module BuildBox.Data.Log ( Log , Line , empty , null , toString , fromString , (<|) , (|>) , (><) , firstLines , lastLines) where import Data.ByteString.Char8 (ByteString) import Data.Sequence (Seq) import qualified Data.ByteString.Char8 as BS import qualified Data.Sequence as Seq import qualified Data.Foldable as F import Prelude hiding (null) -- | A sequence of lines, without newline charaters on the end. type Log = Seq Line type Line = ByteString -- | O(1) No logs here. empty :: Log empty = Seq.empty -- | O(1) Check if the log is empty. null :: Log -> Bool null = Seq.null -- | O(n) Convert a `Log` to a `String`. toString :: Log -> String toString ll = BS.unpack $ BS.intercalate (BS.pack "\n") $ F.toList ll -- | O(n) Convert a `String` to a `Log`. fromString :: String -> Log fromString str = Seq.fromList $ BS.splitWith (== '\n') $ BS.pack str -- | O(1) Add a `Line` to the start of a `Log`. (<|):: Line -> Log -> Log (<|) = (Seq.<|) -- | O(1) Add a `Line` to the end of a `Log`. (|>) :: Log -> Line -> Log (|>) = (Seq.|>) -- | O(log(min(n1,n2))) Concatenate two `Log`s. (><) :: Log -> Log -> Log (><) = (Seq.><) -- | O(n) Take the first m lines from a log firstLines :: Int -> Log -> Log firstLines m ll = Seq.take m ll -- | O(n) Take the last m lines from a log lastLines :: Int -> Log -> Log lastLines m ll = Seq.drop (Seq.length ll - m) ll