dev: lib: Hledger.Utils cleanup, explicit exports
This commit is contained in:
parent
7c8e241383
commit
6fcd85aac3
@ -6,13 +6,83 @@ This is the bottom of hledger's module graph.
|
|||||||
{-# LANGUAGE LambdaCase #-}
|
{-# LANGUAGE LambdaCase #-}
|
||||||
|
|
||||||
module Hledger.Utils (
|
module Hledger.Utils (
|
||||||
module Hledger.Utils,
|
|
||||||
|
-- * Currying
|
||||||
|
curry2,
|
||||||
|
uncurry2,
|
||||||
|
curry3,
|
||||||
|
uncurry3,
|
||||||
|
curry4,
|
||||||
|
uncurry4,
|
||||||
|
|
||||||
|
-- * Console
|
||||||
|
color,
|
||||||
|
bgColor,
|
||||||
|
colorB,
|
||||||
|
bgColorB,
|
||||||
|
|
||||||
|
-- * IO
|
||||||
|
error',
|
||||||
|
usageError,
|
||||||
|
embedFileRelative,
|
||||||
|
expandHomePath,
|
||||||
|
expandPath,
|
||||||
|
readFileOrStdinPortably,
|
||||||
|
readFilePortably,
|
||||||
|
readHandlePortably,
|
||||||
|
-- hereFileRelative,
|
||||||
|
|
||||||
|
-- * Lists
|
||||||
|
splitAtElement,
|
||||||
|
|
||||||
|
-- * Time
|
||||||
|
getCurrentLocalTime,
|
||||||
|
getCurrentZonedTime,
|
||||||
|
|
||||||
|
-- * Trees
|
||||||
|
treeLeaves,
|
||||||
|
|
||||||
|
-- * Tuples
|
||||||
|
first3,
|
||||||
|
second3,
|
||||||
|
third3,
|
||||||
|
first4,
|
||||||
|
second4,
|
||||||
|
third4,
|
||||||
|
fourth4,
|
||||||
|
first5,
|
||||||
|
second5,
|
||||||
|
third5,
|
||||||
|
fourth5,
|
||||||
|
fifth5,
|
||||||
|
first6,
|
||||||
|
second6,
|
||||||
|
third6,
|
||||||
|
fourth6,
|
||||||
|
fifth6,
|
||||||
|
sixth6,
|
||||||
|
|
||||||
|
-- * Misc
|
||||||
|
applyN,
|
||||||
|
mapM',
|
||||||
|
numDigitsInt,
|
||||||
|
maximum',
|
||||||
|
maximumStrict,
|
||||||
|
minimumStrict,
|
||||||
|
sequence',
|
||||||
|
sumStrict,
|
||||||
|
makeHledgerClassyLenses,
|
||||||
|
|
||||||
|
-- * Other
|
||||||
module Hledger.Utils.Debug,
|
module Hledger.Utils.Debug,
|
||||||
module Hledger.Utils.Parse,
|
module Hledger.Utils.Parse,
|
||||||
module Hledger.Utils.Print,
|
module Hledger.Utils.Print,
|
||||||
module Hledger.Utils.Regex,
|
module Hledger.Utils.Regex,
|
||||||
module Hledger.Utils.String,
|
module Hledger.Utils.String,
|
||||||
module Hledger.Utils.Text,
|
module Hledger.Utils.Text,
|
||||||
|
|
||||||
|
-- * Tests
|
||||||
|
tests_Utils,
|
||||||
module Hledger.Utils.Test,
|
module Hledger.Utils.Test,
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
@ -49,31 +119,7 @@ import Hledger.Utils.Text
|
|||||||
import Hledger.Utils.Test
|
import Hledger.Utils.Test
|
||||||
|
|
||||||
|
|
||||||
-- tuples
|
-- Currying
|
||||||
|
|
||||||
first3 (x,_,_) = x
|
|
||||||
second3 (_,x,_) = x
|
|
||||||
third3 (_,_,x) = x
|
|
||||||
|
|
||||||
first4 (x,_,_,_) = x
|
|
||||||
second4 (_,x,_,_) = x
|
|
||||||
third4 (_,_,x,_) = x
|
|
||||||
fourth4 (_,_,_,x) = x
|
|
||||||
|
|
||||||
first5 (x,_,_,_,_) = x
|
|
||||||
second5 (_,x,_,_,_) = x
|
|
||||||
third5 (_,_,x,_,_) = x
|
|
||||||
fourth5 (_,_,_,x,_) = x
|
|
||||||
fifth5 (_,_,_,_,x) = x
|
|
||||||
|
|
||||||
first6 (x,_,_,_,_,_) = x
|
|
||||||
second6 (_,x,_,_,_,_) = x
|
|
||||||
third6 (_,_,x,_,_,_) = x
|
|
||||||
fourth6 (_,_,_,x,_,_) = x
|
|
||||||
fifth6 (_,_,_,_,x,_) = x
|
|
||||||
sixth6 (_,_,_,_,_,x) = x
|
|
||||||
|
|
||||||
-- currying
|
|
||||||
|
|
||||||
curry2 :: ((a, b) -> c) -> a -> b -> c
|
curry2 :: ((a, b) -> c) -> a -> b -> c
|
||||||
curry2 f x y = f (x, y)
|
curry2 f x y = f (x, y)
|
||||||
@ -93,51 +139,27 @@ curry4 f w x y z = f (w, x, y, z)
|
|||||||
uncurry4 :: (a -> b -> c -> d -> e) -> (a, b, c, d) -> e
|
uncurry4 :: (a -> b -> c -> d -> e) -> (a, b, c, d) -> e
|
||||||
uncurry4 f (w, x, y, z) = f w x y z
|
uncurry4 f (w, x, y, z) = f w x y z
|
||||||
|
|
||||||
-- lists
|
-- Console
|
||||||
|
|
||||||
splitAtElement :: Eq a => a -> [a] -> [[a]]
|
-- | Wrap a string in ANSI codes to set and reset foreground colour.
|
||||||
splitAtElement x l =
|
color :: ColorIntensity -> Color -> String -> String
|
||||||
case l of
|
color int col s = setSGRCode [SetColor Foreground int col] ++ s ++ setSGRCode []
|
||||||
[] -> []
|
|
||||||
e:es | e==x -> split es
|
|
||||||
es -> split es
|
|
||||||
where
|
|
||||||
split es = let (first,rest) = break (x==) es
|
|
||||||
in first : splitAtElement x rest
|
|
||||||
|
|
||||||
-- trees
|
-- | Wrap a string in ANSI codes to set and reset background colour.
|
||||||
|
bgColor :: ColorIntensity -> Color -> String -> String
|
||||||
|
bgColor int col s = setSGRCode [SetColor Background int col] ++ s ++ setSGRCode []
|
||||||
|
|
||||||
-- | Get the leaves of this tree as a list.
|
-- | Wrap a WideBuilder in ANSI codes to set and reset foreground colour.
|
||||||
-- The topmost node ("root" in hledger account trees) is not counted as a leaf.
|
colorB :: ColorIntensity -> Color -> WideBuilder -> WideBuilder
|
||||||
treeLeaves :: Show a => Tree a -> [a]
|
colorB int col (WideBuilder s w) =
|
||||||
treeLeaves Node{subForest=[]} = []
|
WideBuilder (TB.fromString (setSGRCode [SetColor Foreground int col]) <> s <> TB.fromString (setSGRCode [])) w
|
||||||
treeLeaves t = foldTree (\a bs -> (if null bs then (a:) else id) $ concat bs) t
|
|
||||||
|
|
||||||
-- time
|
-- | Wrap a WideBuilder in ANSI codes to set and reset background colour.
|
||||||
|
bgColorB :: ColorIntensity -> Color -> WideBuilder -> WideBuilder
|
||||||
|
bgColorB int col (WideBuilder s w) =
|
||||||
|
WideBuilder (TB.fromString (setSGRCode [SetColor Background int col]) <> s <> TB.fromString (setSGRCode [])) w
|
||||||
|
|
||||||
getCurrentLocalTime :: IO LocalTime
|
-- IO
|
||||||
getCurrentLocalTime = do
|
|
||||||
t <- getCurrentTime
|
|
||||||
tz <- getCurrentTimeZone
|
|
||||||
return $ utcToLocalTime tz t
|
|
||||||
|
|
||||||
getCurrentZonedTime :: IO ZonedTime
|
|
||||||
getCurrentZonedTime = do
|
|
||||||
t <- getCurrentTime
|
|
||||||
tz <- getCurrentTimeZone
|
|
||||||
return $ utcToZonedTime tz t
|
|
||||||
|
|
||||||
-- misc
|
|
||||||
|
|
||||||
-- | Apply a function the specified number of times,
|
|
||||||
-- which should be > 0 (otherwise does nothing).
|
|
||||||
-- Possibly uses O(n) stack ?
|
|
||||||
applyN :: Int -> (a -> a) -> a -> a
|
|
||||||
applyN n f | n < 1 = id
|
|
||||||
| otherwise = (!! n) . iterate f
|
|
||||||
-- from protolude, compare
|
|
||||||
-- applyN :: Int -> (a -> a) -> a -> a
|
|
||||||
-- applyN n f = X.foldr (.) identity (X.replicate n f)
|
|
||||||
|
|
||||||
-- | Convert a possibly relative, possibly tilde-containing file path to an absolute one,
|
-- | Convert a possibly relative, possibly tilde-containing file path to an absolute one,
|
||||||
-- given the current directory. ~username is not supported. Leave "-" unchanged.
|
-- given the current directory. ~username is not supported. Leave "-" unchanged.
|
||||||
@ -178,6 +200,96 @@ readHandlePortably h = do
|
|||||||
hSetEncoding h utf8_bom
|
hSetEncoding h utf8_bom
|
||||||
T.hGetContents h
|
T.hGetContents h
|
||||||
|
|
||||||
|
-- | Simpler alias for errorWithoutStackTrace
|
||||||
|
error' :: String -> a
|
||||||
|
error' = errorWithoutStackTrace . ("Error: " <>)
|
||||||
|
|
||||||
|
-- | A version of errorWithoutStackTrace that adds a usage hint.
|
||||||
|
usageError :: String -> a
|
||||||
|
usageError = error' . (++ " (use -h to see usage)")
|
||||||
|
|
||||||
|
-- | Like embedFile, but takes a path relative to the package directory.
|
||||||
|
-- Similar to embedFileRelative ?
|
||||||
|
embedFileRelative :: FilePath -> Q Exp
|
||||||
|
embedFileRelative f = makeRelativeToProject f >>= embedStringFile
|
||||||
|
|
||||||
|
-- -- | Like hereFile, but takes a path relative to the package directory.
|
||||||
|
-- -- Similar to embedFileRelative ?
|
||||||
|
-- hereFileRelative :: FilePath -> Q Exp
|
||||||
|
-- hereFileRelative f = makeRelativeToProject f >>= hereFileExp
|
||||||
|
-- where
|
||||||
|
-- QuasiQuoter{quoteExp=hereFileExp} = hereFile
|
||||||
|
|
||||||
|
-- Lists
|
||||||
|
|
||||||
|
splitAtElement :: Eq a => a -> [a] -> [[a]]
|
||||||
|
splitAtElement x l =
|
||||||
|
case l of
|
||||||
|
[] -> []
|
||||||
|
e:es | e==x -> split es
|
||||||
|
es -> split es
|
||||||
|
where
|
||||||
|
split es = let (first,rest) = break (x==) es
|
||||||
|
in first : splitAtElement x rest
|
||||||
|
|
||||||
|
-- Time
|
||||||
|
|
||||||
|
getCurrentLocalTime :: IO LocalTime
|
||||||
|
getCurrentLocalTime = do
|
||||||
|
t <- getCurrentTime
|
||||||
|
tz <- getCurrentTimeZone
|
||||||
|
return $ utcToLocalTime tz t
|
||||||
|
|
||||||
|
getCurrentZonedTime :: IO ZonedTime
|
||||||
|
getCurrentZonedTime = do
|
||||||
|
t <- getCurrentTime
|
||||||
|
tz <- getCurrentTimeZone
|
||||||
|
return $ utcToZonedTime tz t
|
||||||
|
|
||||||
|
-- Trees
|
||||||
|
|
||||||
|
-- | Get the leaves of this tree as a list.
|
||||||
|
-- The topmost node ("root" in hledger account trees) is not counted as a leaf.
|
||||||
|
treeLeaves :: Tree a -> [a]
|
||||||
|
treeLeaves Node{subForest=[]} = []
|
||||||
|
treeLeaves t = foldTree (\a bs -> (if null bs then (a:) else id) $ concat bs) t
|
||||||
|
|
||||||
|
-- Tuples
|
||||||
|
|
||||||
|
first3 (x,_,_) = x
|
||||||
|
second3 (_,x,_) = x
|
||||||
|
third3 (_,_,x) = x
|
||||||
|
|
||||||
|
first4 (x,_,_,_) = x
|
||||||
|
second4 (_,x,_,_) = x
|
||||||
|
third4 (_,_,x,_) = x
|
||||||
|
fourth4 (_,_,_,x) = x
|
||||||
|
|
||||||
|
first5 (x,_,_,_,_) = x
|
||||||
|
second5 (_,x,_,_,_) = x
|
||||||
|
third5 (_,_,x,_,_) = x
|
||||||
|
fourth5 (_,_,_,x,_) = x
|
||||||
|
fifth5 (_,_,_,_,x) = x
|
||||||
|
|
||||||
|
first6 (x,_,_,_,_,_) = x
|
||||||
|
second6 (_,x,_,_,_,_) = x
|
||||||
|
third6 (_,_,x,_,_,_) = x
|
||||||
|
fourth6 (_,_,_,x,_,_) = x
|
||||||
|
fifth6 (_,_,_,_,x,_) = x
|
||||||
|
sixth6 (_,_,_,_,_,x) = x
|
||||||
|
|
||||||
|
-- Misc
|
||||||
|
|
||||||
|
-- | Apply a function the specified number of times,
|
||||||
|
-- which should be > 0 (otherwise does nothing).
|
||||||
|
-- Possibly uses O(n) stack ?
|
||||||
|
applyN :: Int -> (a -> a) -> a -> a
|
||||||
|
applyN n f | n < 1 = id
|
||||||
|
| otherwise = (!! n) . iterate f
|
||||||
|
-- from protolude, compare
|
||||||
|
-- applyN :: Int -> (a -> a) -> a -> a
|
||||||
|
-- applyN n f = X.foldr (.) identity (X.replicate n f)
|
||||||
|
|
||||||
-- | Total version of maximum, for integral types, giving 0 for an empty list.
|
-- | Total version of maximum, for integral types, giving 0 for an empty list.
|
||||||
maximum' :: Integral a => [a] -> a
|
maximum' :: Integral a => [a] -> a
|
||||||
maximum' [] = 0
|
maximum' [] = 0
|
||||||
@ -220,6 +332,7 @@ mapM' :: Monad f => (a -> f b) -> [a] -> f [b]
|
|||||||
mapM' f = sequence' . map f
|
mapM' f = sequence' . map f
|
||||||
|
|
||||||
-- | Find the number of digits of an 'Int'.
|
-- | Find the number of digits of an 'Int'.
|
||||||
|
{-# INLINE numDigitsInt #-}
|
||||||
numDigitsInt :: Integral a => Int -> a
|
numDigitsInt :: Integral a => Int -> a
|
||||||
numDigitsInt n
|
numDigitsInt n
|
||||||
| n == minBound = 19 -- negate minBound is out of the range of Int
|
| n == minBound = 19 -- negate minBound is out of the range of Int
|
||||||
@ -233,46 +346,6 @@ numDigitsInt n
|
|||||||
| a >= 10000000000000000 = 16 + go (a `quot` 10000000000000000)
|
| a >= 10000000000000000 = 16 + go (a `quot` 10000000000000000)
|
||||||
| a >= 100000000 = 8 + go (a `quot` 100000000)
|
| a >= 100000000 = 8 + go (a `quot` 100000000)
|
||||||
| otherwise = 4 + go (a `quot` 10000)
|
| otherwise = 4 + go (a `quot` 10000)
|
||||||
{-# INLINE numDigitsInt #-}
|
|
||||||
|
|
||||||
-- | Simpler alias for errorWithoutStackTrace
|
|
||||||
error' :: String -> a
|
|
||||||
error' = errorWithoutStackTrace . ("Error: " <>)
|
|
||||||
|
|
||||||
-- | A version of errorWithoutStackTrace that adds a usage hint.
|
|
||||||
usageError :: String -> a
|
|
||||||
usageError = error' . (++ " (use -h to see usage)")
|
|
||||||
|
|
||||||
-- | Like embedFile, but takes a path relative to the package directory.
|
|
||||||
-- Similar to embedFileRelative ?
|
|
||||||
embedFileRelative :: FilePath -> Q Exp
|
|
||||||
embedFileRelative f = makeRelativeToProject f >>= embedStringFile
|
|
||||||
|
|
||||||
-- -- | Like hereFile, but takes a path relative to the package directory.
|
|
||||||
-- -- Similar to embedFileRelative ?
|
|
||||||
-- hereFileRelative :: FilePath -> Q Exp
|
|
||||||
-- hereFileRelative f = makeRelativeToProject f >>= hereFileExp
|
|
||||||
-- where
|
|
||||||
-- QuasiQuoter{quoteExp=hereFileExp} = hereFile
|
|
||||||
|
|
||||||
-- | Wrap a string in ANSI codes to set and reset foreground colour.
|
|
||||||
color :: ColorIntensity -> Color -> String -> String
|
|
||||||
color int col s = setSGRCode [SetColor Foreground int col] ++ s ++ setSGRCode []
|
|
||||||
|
|
||||||
-- | Wrap a string in ANSI codes to set and reset background colour.
|
|
||||||
bgColor :: ColorIntensity -> Color -> String -> String
|
|
||||||
bgColor int col s = setSGRCode [SetColor Background int col] ++ s ++ setSGRCode []
|
|
||||||
|
|
||||||
-- | Wrap a WideBuilder in ANSI codes to set and reset foreground colour.
|
|
||||||
colorB :: ColorIntensity -> Color -> WideBuilder -> WideBuilder
|
|
||||||
colorB int col (WideBuilder s w) =
|
|
||||||
WideBuilder (TB.fromString (setSGRCode [SetColor Foreground int col]) <> s <> TB.fromString (setSGRCode [])) w
|
|
||||||
|
|
||||||
-- | Wrap a WideBuilder in ANSI codes to set and reset background colour.
|
|
||||||
bgColorB :: ColorIntensity -> Color -> WideBuilder -> WideBuilder
|
|
||||||
bgColorB int col (WideBuilder s w) =
|
|
||||||
WideBuilder (TB.fromString (setSGRCode [SetColor Background int col]) <> s <> TB.fromString (setSGRCode [])) w
|
|
||||||
|
|
||||||
|
|
||||||
-- | Make classy lenses for Hledger options fields.
|
-- | Make classy lenses for Hledger options fields.
|
||||||
-- This is intended to be used with BalancingOpts, InputOpt, ReportOpts,
|
-- This is intended to be used with BalancingOpts, InputOpt, ReportOpts,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user