{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
module Hledger.Cli.Commands.Register (
registermode
,register
,postingsReportAsText
,postingsReportItemAsText
,tests_Register
) where
import Data.List
import Data.Maybe
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import System.Console.CmdArgs.Explicit
import Hledger.Read.CsvReader (CSV, CsvRecord, printCSV)
import Hledger
import Hledger.Cli.CliOptions
import Hledger.Cli.Utils
registermode :: Mode RawOpts
registermode = CommandDoc
-> [Flag RawOpts]
-> [(CommandDoc, [Flag RawOpts])]
-> [Flag RawOpts]
-> ([Arg RawOpts], Maybe (Arg RawOpts))
-> Mode RawOpts
hledgerCommandMode
$(embedFileRelative "Hledger/Cli/Commands/Register.txt")
([[CommandDoc] -> (RawOpts -> RawOpts) -> CommandDoc -> Flag RawOpts
forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"cumulative"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"change")
CommandDoc
"show running total from report start date (default)"
,[CommandDoc] -> (RawOpts -> RawOpts) -> CommandDoc -> Flag RawOpts
forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"historical",CommandDoc
"H"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"historical")
CommandDoc
"show historical running total/balance (includes postings before report start date)\n "
,[CommandDoc] -> (RawOpts -> RawOpts) -> CommandDoc -> Flag RawOpts
forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"average",CommandDoc
"A"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"average")
CommandDoc
"show running average of posting amounts instead of total (implies --empty)"
,[CommandDoc] -> (RawOpts -> RawOpts) -> CommandDoc -> Flag RawOpts
forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"related",CommandDoc
"r"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"related") CommandDoc
"show postings' siblings instead"
,[CommandDoc] -> (RawOpts -> RawOpts) -> CommandDoc -> Flag RawOpts
forall a. [CommandDoc] -> (a -> a) -> CommandDoc -> Flag a
flagNone [CommandDoc
"invert"] (CommandDoc -> RawOpts -> RawOpts
setboolopt CommandDoc
"invert") CommandDoc
"display all amounts with reversed sign"
,[CommandDoc]
-> Update RawOpts -> CommandDoc -> CommandDoc -> Flag RawOpts
forall a.
[CommandDoc] -> Update a -> CommandDoc -> CommandDoc -> Flag a
flagReq [CommandDoc
"width",CommandDoc
"w"] (\CommandDoc
s RawOpts
opts -> RawOpts -> Either CommandDoc RawOpts
forall a b. b -> Either a b
Right (RawOpts -> Either CommandDoc RawOpts)
-> RawOpts -> Either CommandDoc RawOpts
forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc -> RawOpts -> RawOpts
setopt CommandDoc
"width" CommandDoc
s RawOpts
opts) CommandDoc
"N"
(CommandDoc
"set output width (default: " CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++
#ifdef mingw32_HOST_OS
show defaultWidth
#else
CommandDoc
"terminal width"
#endif
CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++ CommandDoc
" or $COLUMNS). -wN,M sets description width as well."
)
,[CommandDoc] -> Flag RawOpts
outputFormatFlag [CommandDoc
"txt",CommandDoc
"csv",CommandDoc
"json"]
,Flag RawOpts
outputFileFlag
])
[(CommandDoc, [Flag RawOpts])
generalflagsgroup1]
[Flag RawOpts]
hiddenflags
([], Arg RawOpts -> Maybe (Arg RawOpts)
forall a. a -> Maybe a
Just (Arg RawOpts -> Maybe (Arg RawOpts))
-> Arg RawOpts -> Maybe (Arg RawOpts)
forall a b. (a -> b) -> a -> b
$ CommandDoc -> Arg RawOpts
argsFlag CommandDoc
"[QUERY]")
register :: CliOpts -> Journal -> IO ()
register :: CliOpts -> Journal -> IO ()
register opts :: CliOpts
opts@CliOpts{reportspec_ :: CliOpts -> ReportSpec
reportspec_=ReportSpec
rspec} Journal
j = do
let fmt :: CommandDoc
fmt = CliOpts -> CommandDoc
outputFormatFromOpts CliOpts
opts
render :: CliOpts -> PostingsReport -> CommandDoc
render | CommandDoc
fmtCommandDoc -> CommandDoc -> Bool
forall a. Eq a => a -> a -> Bool
==CommandDoc
"txt" = CliOpts -> PostingsReport -> CommandDoc
postingsReportAsText
| CommandDoc
fmtCommandDoc -> CommandDoc -> Bool
forall a. Eq a => a -> a -> Bool
==CommandDoc
"csv" = (PostingsReport -> CommandDoc)
-> CliOpts -> PostingsReport -> CommandDoc
forall a b. a -> b -> a
const ((CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
"\n") (CommandDoc -> CommandDoc)
-> (PostingsReport -> CommandDoc) -> PostingsReport -> CommandDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CSV -> CommandDoc
printCSV (CSV -> CommandDoc)
-> (PostingsReport -> CSV) -> PostingsReport -> CommandDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PostingsReport -> CSV
postingsReportAsCsv)
| CommandDoc
fmtCommandDoc -> CommandDoc -> Bool
forall a. Eq a => a -> a -> Bool
==CommandDoc
"json" = (PostingsReport -> CommandDoc)
-> CliOpts -> PostingsReport -> CommandDoc
forall a b. a -> b -> a
const ((CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
"\n") (CommandDoc -> CommandDoc)
-> (PostingsReport -> CommandDoc) -> PostingsReport -> CommandDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> CommandDoc
TL.unpack (Text -> CommandDoc)
-> (PostingsReport -> Text) -> PostingsReport -> CommandDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PostingsReport -> Text
forall a. ToJSON a => a -> Text
toJsonText)
| Bool
otherwise = (PostingsReport -> CommandDoc)
-> CliOpts -> PostingsReport -> CommandDoc
forall a b. a -> b -> a
const ((PostingsReport -> CommandDoc)
-> CliOpts -> PostingsReport -> CommandDoc)
-> (PostingsReport -> CommandDoc)
-> CliOpts
-> PostingsReport
-> CommandDoc
forall a b. (a -> b) -> a -> b
$ CommandDoc -> PostingsReport -> CommandDoc
forall a. CommandDoc -> a
error' (CommandDoc -> PostingsReport -> CommandDoc)
-> CommandDoc -> PostingsReport -> CommandDoc
forall a b. (a -> b) -> a -> b
$ CommandDoc -> CommandDoc
unsupportedOutputFormatError CommandDoc
fmt
CliOpts -> CommandDoc -> IO ()
writeOutput CliOpts
opts (CommandDoc -> IO ())
-> (PostingsReport -> CommandDoc) -> PostingsReport -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. CliOpts -> PostingsReport -> CommandDoc
render CliOpts
opts (PostingsReport -> IO ()) -> PostingsReport -> IO ()
forall a b. (a -> b) -> a -> b
$ ReportSpec -> Journal -> PostingsReport
postingsReport ReportSpec
rspec Journal
j
postingsReportAsCsv :: PostingsReport -> CSV
postingsReportAsCsv :: PostingsReport -> CSV
postingsReportAsCsv (CommandDoc
_,[PostingsReportItem]
is) =
[CommandDoc
"txnidx",CommandDoc
"date",CommandDoc
"code",CommandDoc
"description",CommandDoc
"account",CommandDoc
"amount",CommandDoc
"total"]
[CommandDoc] -> CSV -> CSV
forall a. a -> [a] -> [a]
:
(PostingsReportItem -> [CommandDoc]) -> [PostingsReportItem] -> CSV
forall a b. (a -> b) -> [a] -> [b]
map PostingsReportItem -> [CommandDoc]
postingsReportItemAsCsvRecord [PostingsReportItem]
is
postingsReportItemAsCsvRecord :: PostingsReportItem -> CsvRecord
postingsReportItemAsCsvRecord :: PostingsReportItem -> [CommandDoc]
postingsReportItemAsCsvRecord (Maybe Day
_, Maybe Day
_, Maybe CommandDoc
_, Posting
p, MixedAmount
b) = [CommandDoc
idx,CommandDoc
date,CommandDoc
code,CommandDoc
desc,CommandDoc
acct,CommandDoc
amt,CommandDoc
bal]
where
idx :: CommandDoc
idx = Integer -> CommandDoc
forall a. Show a => a -> CommandDoc
show (Integer -> CommandDoc) -> Integer -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Integer -> (Transaction -> Integer) -> Maybe Transaction -> Integer
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Integer
0 Transaction -> Integer
tindex (Maybe Transaction -> Integer) -> Maybe Transaction -> Integer
forall a b. (a -> b) -> a -> b
$ Posting -> Maybe Transaction
ptransaction Posting
p
date :: CommandDoc
date = Day -> CommandDoc
showDate (Day -> CommandDoc) -> Day -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Posting -> Day
postingDate Posting
p
code :: CommandDoc
code = CommandDoc
-> (Transaction -> CommandDoc) -> Maybe Transaction -> CommandDoc
forall b a. b -> (a -> b) -> Maybe a -> b
maybe CommandDoc
"" (Text -> CommandDoc
T.unpack (Text -> CommandDoc)
-> (Transaction -> Text) -> Transaction -> CommandDoc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Transaction -> Text
tcode) (Maybe Transaction -> CommandDoc)
-> Maybe Transaction -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Posting -> Maybe Transaction
ptransaction Posting
p
desc :: CommandDoc
desc = Text -> CommandDoc
T.unpack (Text -> CommandDoc) -> Text -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Text -> (Transaction -> Text) -> Maybe Transaction -> Text
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Text
"" Transaction -> Text
tdescription (Maybe Transaction -> Text) -> Maybe Transaction -> Text
forall a b. (a -> b) -> a -> b
$ Posting -> Maybe Transaction
ptransaction Posting
p
acct :: CommandDoc
acct = CommandDoc -> CommandDoc
bracket (CommandDoc -> CommandDoc) -> CommandDoc -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Text -> CommandDoc
T.unpack (Text -> CommandDoc) -> Text -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Posting -> Text
paccount Posting
p
where
bracket :: CommandDoc -> CommandDoc
bracket = case Posting -> PostingType
ptype Posting
p of
PostingType
BalancedVirtualPosting -> (\CommandDoc
s -> CommandDoc
"["CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
sCommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
"]")
PostingType
VirtualPosting -> (\CommandDoc
s -> CommandDoc
"("CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
sCommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
")")
PostingType
_ -> CommandDoc -> CommandDoc
forall a. a -> a
id
amt :: CommandDoc
amt = Bool -> MixedAmount -> CommandDoc
showMixedAmountOneLineWithoutPrice Bool
False (MixedAmount -> CommandDoc) -> MixedAmount -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Posting -> MixedAmount
pamount Posting
p
bal :: CommandDoc
bal = Bool -> MixedAmount -> CommandDoc
showMixedAmountOneLineWithoutPrice Bool
False MixedAmount
b
postingsReportAsText :: CliOpts -> PostingsReport -> String
postingsReportAsText :: CliOpts -> PostingsReport -> CommandDoc
postingsReportAsText CliOpts
opts (CommandDoc
_,[PostingsReportItem]
items) = [CommandDoc] -> CommandDoc
unlines ([CommandDoc] -> CommandDoc) -> [CommandDoc] -> CommandDoc
forall a b. (a -> b) -> a -> b
$ (PostingsReportItem -> CommandDoc)
-> [PostingsReportItem] -> [CommandDoc]
forall a b. (a -> b) -> [a] -> [b]
map (CliOpts -> Int -> Int -> PostingsReportItem -> CommandDoc
postingsReportItemAsText CliOpts
opts Int
amtwidth Int
balwidth) [PostingsReportItem]
items
where
amtwidth :: Int
amtwidth = [Int] -> Int
forall a. Ord a => [a] -> a
maximumStrict ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (PostingsReportItem -> Int) -> [PostingsReportItem] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map ((CommandDoc, Int) -> Int
forall a b. (a, b) -> b
snd ((CommandDoc, Int) -> Int)
-> (PostingsReportItem -> (CommandDoc, Int))
-> PostingsReportItem
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Amount -> CommandDoc)
-> Maybe Int
-> Maybe Int
-> Bool
-> MixedAmount
-> (CommandDoc, Int)
showMixed Amount -> CommandDoc
showAmount (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
12) Maybe Int
forall a. Maybe a
Nothing Bool
False (MixedAmount -> (CommandDoc, Int))
-> (PostingsReportItem -> MixedAmount)
-> PostingsReportItem
-> (CommandDoc, Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PostingsReportItem -> MixedAmount
forall a b c e. (a, b, c, Posting, e) -> MixedAmount
itemamt) [PostingsReportItem]
items
balwidth :: Int
balwidth = [Int] -> Int
forall a. Ord a => [a] -> a
maximumStrict ([Int] -> Int) -> [Int] -> Int
forall a b. (a -> b) -> a -> b
$ (PostingsReportItem -> Int) -> [PostingsReportItem] -> [Int]
forall a b. (a -> b) -> [a] -> [b]
map ((CommandDoc, Int) -> Int
forall a b. (a, b) -> b
snd ((CommandDoc, Int) -> Int)
-> (PostingsReportItem -> (CommandDoc, Int))
-> PostingsReportItem
-> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Amount -> CommandDoc)
-> Maybe Int
-> Maybe Int
-> Bool
-> MixedAmount
-> (CommandDoc, Int)
showMixed Amount -> CommandDoc
showAmount (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
12) Maybe Int
forall a. Maybe a
Nothing Bool
False (MixedAmount -> (CommandDoc, Int))
-> (PostingsReportItem -> MixedAmount)
-> PostingsReportItem
-> (CommandDoc, Int)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PostingsReportItem -> MixedAmount
forall a b c d e. (a, b, c, d, e) -> e
itembal) [PostingsReportItem]
items
itemamt :: (a, b, c, Posting, e) -> MixedAmount
itemamt (a
_,b
_,c
_,Posting{pamount :: Posting -> MixedAmount
pamount=MixedAmount
a},e
_) = MixedAmount
a
itembal :: (a, b, c, d, e) -> e
itembal (a
_,b
_,c
_,d
_,e
a) = e
a
postingsReportItemAsText :: CliOpts -> Int -> Int -> PostingsReportItem -> String
postingsReportItemAsText :: CliOpts -> Int -> Int -> PostingsReportItem -> CommandDoc
postingsReportItemAsText CliOpts
opts Int
preferredamtwidth Int
preferredbalwidth (Maybe Day
mdate, Maybe Day
menddate, Maybe CommandDoc
mdesc, Posting
p, MixedAmount
b) =
CommandDoc -> [CommandDoc] -> CommandDoc
forall a. [a] -> [[a]] -> [a]
intercalate CommandDoc
"\n" ([CommandDoc] -> CommandDoc) -> [CommandDoc] -> CommandDoc
forall a b. (a -> b) -> a -> b
$
[CommandDoc] -> CommandDoc
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [Maybe Int -> Maybe Int -> Bool -> Bool -> CommandDoc -> CommandDoc
fitString (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
datewidth) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
datewidth) Bool
True Bool
True CommandDoc
date
,CommandDoc
" "
,Maybe Int -> Maybe Int -> Bool -> Bool -> CommandDoc -> CommandDoc
fitString (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
descwidth) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
descwidth) Bool
True Bool
True CommandDoc
desc
,CommandDoc
" "
,Maybe Int -> Maybe Int -> Bool -> Bool -> CommandDoc -> CommandDoc
fitString (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
acctwidth) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
acctwidth) Bool
True Bool
True CommandDoc
acct
,CommandDoc
" "
,CommandDoc
amtfirstline
,CommandDoc
" "
,CommandDoc
balfirstline
]
CommandDoc -> [CommandDoc] -> [CommandDoc]
forall a. a -> [a] -> [a]
:
[[CommandDoc] -> CommandDoc
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat [CommandDoc
spacer
,CommandDoc
a
,CommandDoc
" "
,CommandDoc
b
]
| (CommandDoc
a,CommandDoc
b) <- [CommandDoc] -> [CommandDoc] -> [(CommandDoc, CommandDoc)]
forall a b. [a] -> [b] -> [(a, b)]
zip [CommandDoc]
amtrest [CommandDoc]
balrest
]
where
(Int
totalwidth,Maybe Int
mdescwidth) = CliOpts -> (Int, Maybe Int)
registerWidthsFromOpts CliOpts
opts
(Int
datewidth, CommandDoc
date) = case (Maybe Day
mdate,Maybe Day
menddate) of
(Just Day
_, Just Day
_) -> (Int
21, DateSpan -> CommandDoc
showDateSpan (Maybe Day -> Maybe Day -> DateSpan
DateSpan Maybe Day
mdate Maybe Day
menddate))
(Maybe Day
Nothing, Just Day
_) -> (Int
21, CommandDoc
"")
(Just Day
d, Maybe Day
Nothing) -> (Int
10, Day -> CommandDoc
showDate Day
d)
(Maybe Day, Maybe Day)
_ -> (Int
10, CommandDoc
"")
(Int
amtwidth, Int
balwidth)
| Int
shortfall Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0 = (Int
preferredamtwidth, Int
preferredbalwidth)
| Bool
otherwise = (Int
adjustedamtwidth, Int
adjustedbalwidth)
where
mincolwidth :: Int
mincolwidth = Int
2
maxamtswidth :: Int
maxamtswidth = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
0 (Int
totalwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
- (Int
datewidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
mincolwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
mincolwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2))
shortfall :: Int
shortfall = (Int
preferredamtwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
preferredbalwidth) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
maxamtswidth
amtwidthproportion :: Double
amtwidthproportion = Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
preferredamtwidth Double -> Double -> Double
forall a. Fractional a => a -> a -> a
/ Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
preferredamtwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
preferredbalwidth)
adjustedamtwidth :: Int
adjustedamtwidth = Double -> Int
forall a b. (RealFrac a, Integral b) => a -> b
round (Double -> Int) -> Double -> Int
forall a b. (a -> b) -> a -> b
$ Double
amtwidthproportion Double -> Double -> Double
forall a. Num a => a -> a -> a
* Int -> Double
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
maxamtswidth
adjustedbalwidth :: Int
adjustedbalwidth = Int
maxamtswidth Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
adjustedamtwidth
remaining :: Int
remaining = Int
totalwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
- (Int
datewidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
amtwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
balwidth)
(Int
descwidth, Int
acctwidth)
| Bool
hasinterval = (Int
0, Int
remaining Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2)
| Bool
otherwise = (Int
w, Int
remaining Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
w)
where
hasinterval :: Bool
hasinterval = Maybe Day -> Bool
forall a. Maybe a -> Bool
isJust Maybe Day
menddate
w :: Int
w = Int -> Maybe Int -> Int
forall a. a -> Maybe a -> a
fromMaybe ((Int
remaining Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
2) Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Int
2) Maybe Int
mdescwidth
desc :: CommandDoc
desc = CommandDoc -> Maybe CommandDoc -> CommandDoc
forall a. a -> Maybe a -> a
fromMaybe CommandDoc
"" Maybe CommandDoc
mdesc
acct :: CommandDoc
acct = CommandDoc -> CommandDoc
parenthesise (CommandDoc -> CommandDoc) -> CommandDoc -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Text -> CommandDoc
T.unpack (Text -> CommandDoc) -> Text -> CommandDoc
forall a b. (a -> b) -> a -> b
$ Int -> Text -> Text
elideAccountName Int
awidth (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ Posting -> Text
paccount Posting
p
where
(CommandDoc -> CommandDoc
parenthesise, Int
awidth) =
case Posting -> PostingType
ptype Posting
p of
PostingType
BalancedVirtualPosting -> (\CommandDoc
s -> CommandDoc
"["CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
sCommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
"]", Int
acctwidthInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
2)
PostingType
VirtualPosting -> (\CommandDoc
s -> CommandDoc
"("CommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
sCommandDoc -> CommandDoc -> CommandDoc
forall a. [a] -> [a] -> [a]
++CommandDoc
")", Int
acctwidthInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
2)
PostingType
_ -> (CommandDoc -> CommandDoc
forall a. a -> a
id,Int
acctwidth)
amt :: CommandDoc
amt = (CommandDoc, Int) -> CommandDoc
forall a b. (a, b) -> a
fst ((CommandDoc, Int) -> CommandDoc)
-> (CommandDoc, Int) -> CommandDoc
forall a b. (a -> b) -> a -> b
$ (Amount -> CommandDoc)
-> Maybe Int
-> Maybe Int
-> Bool
-> MixedAmount
-> (CommandDoc, Int)
showMixed Amount -> CommandDoc
showAmountWithoutPrice (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
amtwidth) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
amtwidth) (ReportOpts -> Bool
color_ (ReportOpts -> Bool)
-> (ReportSpec -> ReportOpts) -> ReportSpec -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReportSpec -> ReportOpts
rsOpts (ReportSpec -> Bool) -> ReportSpec -> Bool
forall a b. (a -> b) -> a -> b
$ CliOpts -> ReportSpec
reportspec_ CliOpts
opts) (MixedAmount -> (CommandDoc, Int))
-> MixedAmount -> (CommandDoc, Int)
forall a b. (a -> b) -> a -> b
$ Posting -> MixedAmount
pamount Posting
p
bal :: CommandDoc
bal = (CommandDoc, Int) -> CommandDoc
forall a b. (a, b) -> a
fst ((CommandDoc, Int) -> CommandDoc)
-> (CommandDoc, Int) -> CommandDoc
forall a b. (a -> b) -> a -> b
$ (Amount -> CommandDoc)
-> Maybe Int
-> Maybe Int
-> Bool
-> MixedAmount
-> (CommandDoc, Int)
showMixed Amount -> CommandDoc
showAmountWithoutPrice (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
balwidth) (Int -> Maybe Int
forall a. a -> Maybe a
Just Int
balwidth) (ReportOpts -> Bool
color_ (ReportOpts -> Bool)
-> (ReportSpec -> ReportOpts) -> ReportSpec -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReportSpec -> ReportOpts
rsOpts (ReportSpec -> Bool) -> ReportSpec -> Bool
forall a b. (a -> b) -> a -> b
$ CliOpts -> ReportSpec
reportspec_ CliOpts
opts) MixedAmount
b
([CommandDoc]
amtlines, [CommandDoc]
ballines) = (CommandDoc -> [CommandDoc]
lines CommandDoc
amt, CommandDoc -> [CommandDoc]
lines CommandDoc
bal)
(Int
amtlen, Int
ballen) = ([CommandDoc] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [CommandDoc]
amtlines, [CommandDoc] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [CommandDoc]
ballines)
numlines :: Int
numlines = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1 (Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
amtlen Int
ballen)
(CommandDoc
amtfirstline:[CommandDoc]
amtrest) = Int -> [CommandDoc] -> [CommandDoc]
forall a. Int -> [a] -> [a]
take Int
numlines ([CommandDoc] -> [CommandDoc]) -> [CommandDoc] -> [CommandDoc]
forall a b. (a -> b) -> a -> b
$ [CommandDoc]
amtlines [CommandDoc] -> [CommandDoc] -> [CommandDoc]
forall a. [a] -> [a] -> [a]
++ CommandDoc -> [CommandDoc]
forall a. a -> [a]
repeat (Int -> Char -> CommandDoc
forall a. Int -> a -> [a]
replicate Int
amtwidth Char
' ')
(CommandDoc
balfirstline:[CommandDoc]
balrest) = Int -> [CommandDoc] -> [CommandDoc]
forall a. Int -> [a] -> [a]
take Int
numlines ([CommandDoc] -> [CommandDoc]) -> [CommandDoc] -> [CommandDoc]
forall a b. (a -> b) -> a -> b
$ Int -> CommandDoc -> [CommandDoc]
forall a. Int -> a -> [a]
replicate (Int
numlines Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
ballen) (Int -> Char -> CommandDoc
forall a. Int -> a -> [a]
replicate Int
balwidth Char
' ') [CommandDoc] -> [CommandDoc] -> [CommandDoc]
forall a. [a] -> [a] -> [a]
++ [CommandDoc]
ballines
spacer :: CommandDoc
spacer = Int -> Char -> CommandDoc
forall a. Int -> a -> [a]
replicate (Int
totalwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
- (Int
amtwidth Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
balwidth)) Char
' '
tests_Register :: TestTree
tests_Register = CommandDoc -> [TestTree] -> TestTree
tests CommandDoc
"Register" [
CommandDoc -> [TestTree] -> TestTree
tests CommandDoc
"postingsReportAsText" [
CommandDoc -> IO () -> TestTree
test CommandDoc
"unicode in register layout" (IO () -> TestTree) -> IO () -> TestTree
forall a b. (a -> b) -> a -> b
$ do
Journal
j <- Text -> IO Journal
readJournal' Text
"2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n"
let rspec :: ReportSpec
rspec = ReportSpec
defreportspec
(CliOpts -> PostingsReport -> CommandDoc
postingsReportAsText CliOpts
defcliopts (PostingsReport -> CommandDoc) -> PostingsReport -> CommandDoc
forall a b. (a -> b) -> a -> b
$ ReportSpec -> Journal -> PostingsReport
postingsReport ReportSpec
rspec Journal
j)
CommandDoc -> CommandDoc -> IO ()
forall a. (Eq a, Show a, HasCallStack) => a -> a -> IO ()
@?=
[CommandDoc] -> CommandDoc
unlines
[CommandDoc
"2009-01-01 медвежья шкура расходы:покупки 100 100"
,CommandDoc
" актив:наличные -100 0"]
]
]