2008-10-03 06:04:15 +04:00
|
|
|
{-|
|
|
|
|
|
2010-05-27 07:58:47 +04:00
|
|
|
Standard imports and utilities which are useful everywhere, or needed low
|
|
|
|
in the module hierarchy. This is the bottom of hledger's module graph.
|
2008-10-03 06:04:15 +04:00
|
|
|
|
|
|
|
-}
|
|
|
|
|
2011-05-28 08:11:44 +04:00
|
|
|
module Hledger.Utils (---- provide these frequently used modules - or not, for clearer api:
|
|
|
|
-- module Control.Monad,
|
|
|
|
-- module Data.List,
|
|
|
|
-- module Data.Maybe,
|
|
|
|
-- module Data.Time.Calendar,
|
|
|
|
-- module Data.Time.Clock,
|
|
|
|
-- module Data.Time.LocalTime,
|
|
|
|
-- module Data.Tree,
|
|
|
|
-- module Text.RegexPR,
|
|
|
|
-- module Test.HUnit,
|
|
|
|
-- module Text.Printf,
|
|
|
|
---- all of this one:
|
2011-08-08 05:34:00 +04:00
|
|
|
module Hledger.Utils,
|
2014-10-29 03:21:33 +03:00
|
|
|
module Hledger.Utils.Debug,
|
2015-08-19 23:47:26 +03:00
|
|
|
module Hledger.Utils.Parse,
|
2014-07-06 21:11:02 +04:00
|
|
|
module Hledger.Utils.Regex,
|
2015-08-19 23:47:26 +03:00
|
|
|
module Hledger.Utils.String,
|
|
|
|
module Hledger.Utils.Test,
|
|
|
|
module Hledger.Utils.Tree,
|
2014-10-29 03:21:33 +03:00
|
|
|
-- Debug.Trace.trace,
|
2014-03-20 03:11:46 +04:00
|
|
|
-- module Data.PPrint,
|
2012-03-29 23:06:31 +04:00
|
|
|
-- module Hledger.Utils.UTF8IOCompat
|
2013-03-29 22:40:10 +04:00
|
|
|
SystemString,fromSystemString,toSystemString,error',userError',
|
2012-03-29 23:06:31 +04:00
|
|
|
-- the rest need to be done in each module I think
|
2011-05-28 08:11:44 +04:00
|
|
|
)
|
2007-02-16 12:00:17 +03:00
|
|
|
where
|
2014-10-29 03:21:33 +03:00
|
|
|
import Control.Monad (liftM)
|
2015-03-30 02:12:05 +03:00
|
|
|
import Control.Monad.IO.Class (MonadIO, liftIO)
|
2015-08-19 23:47:26 +03:00
|
|
|
-- import Data.Char
|
|
|
|
-- import Data.List
|
2014-07-06 21:11:02 +04:00
|
|
|
-- import Data.Maybe
|
2014-03-20 03:11:46 +04:00
|
|
|
-- import Data.PPrint
|
2008-11-22 15:18:19 +03:00
|
|
|
import Data.Time.Clock
|
2008-12-11 04:35:07 +03:00
|
|
|
import Data.Time.LocalTime
|
2012-03-24 22:08:11 +04:00
|
|
|
import System.Directory (getHomeDirectory)
|
2012-05-30 12:36:01 +04:00
|
|
|
import System.FilePath((</>), isRelative)
|
2013-03-29 22:46:10 +04:00
|
|
|
import System.IO
|
2015-08-19 23:47:26 +03:00
|
|
|
-- import Text.Printf
|
2011-05-28 08:11:44 +04:00
|
|
|
-- import qualified Data.Map as Map
|
2014-07-06 21:11:02 +04:00
|
|
|
|
2014-10-29 03:21:33 +03:00
|
|
|
import Hledger.Utils.Debug
|
2015-08-19 23:47:26 +03:00
|
|
|
import Hledger.Utils.Parse
|
2014-07-06 21:11:02 +04:00
|
|
|
import Hledger.Utils.Regex
|
2015-08-19 23:47:26 +03:00
|
|
|
import Hledger.Utils.String
|
|
|
|
import Hledger.Utils.Test
|
|
|
|
import Hledger.Utils.Tree
|
2012-03-29 23:06:31 +04:00
|
|
|
-- import Prelude hiding (readFile,writeFile,appendFile,getContents,putStr,putStrLn)
|
|
|
|
-- import Hledger.Utils.UTF8IOCompat (readFile,writeFile,appendFile,getContents,putStr,putStrLn)
|
|
|
|
import Hledger.Utils.UTF8IOCompat (SystemString,fromSystemString,toSystemString,error',userError')
|
2008-10-10 11:39:20 +04:00
|
|
|
|
2008-12-06 10:15:19 +03:00
|
|
|
|
2014-03-26 22:15:04 +04:00
|
|
|
-- 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
|
|
|
|
|
2007-07-03 03:54:17 +04:00
|
|
|
-- lists
|
|
|
|
|
2007-02-16 12:00:17 +03:00
|
|
|
splitAtElement :: Eq a => a -> [a] -> [[a]]
|
2014-10-25 01:29:34 +04:00
|
|
|
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
|
2007-02-16 12:00:17 +03:00
|
|
|
|
2009-01-25 09:47:05 +03:00
|
|
|
-- time
|
|
|
|
|
|
|
|
getCurrentLocalTime :: IO LocalTime
|
|
|
|
getCurrentLocalTime = do
|
|
|
|
t <- getCurrentTime
|
|
|
|
tz <- getCurrentTimeZone
|
|
|
|
return $ utcToLocalTime tz t
|
2009-04-01 12:55:46 +04:00
|
|
|
|
2009-04-08 09:30:26 +04:00
|
|
|
-- misc
|
2009-04-01 12:55:46 +04:00
|
|
|
|
|
|
|
isLeft :: Either a b -> Bool
|
|
|
|
isLeft (Left _) = True
|
|
|
|
isLeft _ = False
|
|
|
|
|
|
|
|
isRight :: Either a b -> Bool
|
|
|
|
isRight = not . isLeft
|
|
|
|
|
2011-01-14 07:32:08 +03:00
|
|
|
-- | Apply a function the specified number of times. Possibly uses O(n) stack ?
|
|
|
|
applyN :: Int -> (a -> a) -> a -> a
|
|
|
|
applyN n f = (!! n) . iterate f
|
2012-03-24 22:08:11 +04:00
|
|
|
|
2012-05-30 12:36:01 +04:00
|
|
|
-- | Convert a possibly relative, possibly tilde-containing file path to an absolute one,
|
2014-09-11 00:07:53 +04:00
|
|
|
-- given the current directory. ~username is not supported. Leave "-" unchanged.
|
2012-05-30 12:36:01 +04:00
|
|
|
expandPath :: MonadIO m => FilePath -> FilePath -> m FilePath -- general type sig for use in reader parsers
|
|
|
|
expandPath _ "-" = return "-"
|
|
|
|
expandPath curdir p = (if isRelative p then (curdir </>) else id) `liftM` expandPath' p
|
2012-03-24 22:08:11 +04:00
|
|
|
where
|
2012-05-30 12:36:01 +04:00
|
|
|
expandPath' ('~':'/':p) = liftIO $ (</> p) `fmap` getHomeDirectory
|
|
|
|
expandPath' ('~':'\\':p) = liftIO $ (</> p) `fmap` getHomeDirectory
|
|
|
|
expandPath' ('~':_) = error' "~USERNAME in paths is not supported"
|
|
|
|
expandPath' p = return p
|
2012-04-16 20:44:41 +04:00
|
|
|
|
|
|
|
firstJust ms = case dropWhile (==Nothing) ms of
|
|
|
|
[] -> Nothing
|
|
|
|
(md:_) -> md
|
2013-03-29 22:46:10 +04:00
|
|
|
|
|
|
|
-- | Read a file in universal newline mode, handling whatever newline convention it may contain.
|
|
|
|
readFile' :: FilePath -> IO String
|
|
|
|
readFile' name = do
|
|
|
|
h <- openFile name ReadMode
|
|
|
|
hSetNewlineMode h universalNewlineMode
|
|
|
|
hGetContents h
|