mirror of
https://github.com/simonmichael/hledger.git
synced 2024-09-19 18:29:36 +03:00
cli: Using Text Builder for posting reports.
This commit is contained in:
parent
ac39d59016
commit
646ee0bce5
@ -44,7 +44,7 @@ import Data.Decimal
|
|||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import qualified Data.Text.Lazy as TL
|
import qualified Data.Text.Lazy as TL
|
||||||
import qualified Data.Text.Lazy.IO as TL
|
import qualified Data.Text.Lazy.IO as TL
|
||||||
import Data.Text.Lazy.Builder (toLazyText)
|
import qualified Data.Text.Lazy.Builder as TB
|
||||||
import GHC.Generics (Generic)
|
import GHC.Generics (Generic)
|
||||||
import System.Time (ClockTime)
|
import System.Time (ClockTime)
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ instance FromJSON (DecimalRaw Integer)
|
|||||||
|
|
||||||
-- | Show a JSON-convertible haskell value as pretty-printed JSON text.
|
-- | Show a JSON-convertible haskell value as pretty-printed JSON text.
|
||||||
toJsonText :: ToJSON a => a -> TL.Text
|
toJsonText :: ToJSON a => a -> TL.Text
|
||||||
toJsonText = (<>"\n") . toLazyText . encodePrettyToTextBuilder
|
toJsonText = TB.toLazyText . (<> TB.fromText "\n") . encodePrettyToTextBuilder
|
||||||
|
|
||||||
-- | Write a JSON-convertible haskell value to a pretty-printed JSON file.
|
-- | Write a JSON-convertible haskell value to a pretty-printed JSON file.
|
||||||
-- Eg: writeJsonFile "a.json" nulltransaction
|
-- Eg: writeJsonFile "a.json" nulltransaction
|
||||||
|
@ -24,8 +24,7 @@ where
|
|||||||
import Data.List
|
import Data.List
|
||||||
import Data.List.Extra (nubSort)
|
import Data.List.Extra (nubSort)
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
-- import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
|
||||||
import Data.Time.Calendar
|
import Data.Time.Calendar
|
||||||
import Safe (headMay, lastMay)
|
import Safe (headMay, lastMay)
|
||||||
|
|
||||||
@ -38,9 +37,7 @@ import Hledger.Reports.ReportOptions
|
|||||||
-- | A postings report is a list of postings with a running total, a label
|
-- | A postings report is a list of postings with a running total, a label
|
||||||
-- for the total field, and a little extra transaction info to help with rendering.
|
-- for the total field, and a little extra transaction info to help with rendering.
|
||||||
-- This is used eg for the register command.
|
-- This is used eg for the register command.
|
||||||
type PostingsReport = (String -- label for the running balance column XXX remove
|
type PostingsReport = [PostingsReportItem] -- line items, one per posting
|
||||||
,[PostingsReportItem] -- line items, one per posting
|
|
||||||
)
|
|
||||||
type PostingsReportItem = (Maybe Day -- The posting date, if this is the first posting in a
|
type PostingsReportItem = (Maybe Day -- The posting date, if this is the first posting in a
|
||||||
-- transaction or if it's different from the previous
|
-- transaction or if it's different from the previous
|
||||||
-- posting's date. Or if this a summary posting, the
|
-- posting's date. Or if this a summary posting, the
|
||||||
@ -49,7 +46,7 @@ type PostingsReportItem = (Maybe Day -- The posting date, if this is the firs
|
|||||||
,Maybe Day -- If this is a summary posting, the report interval's
|
,Maybe Day -- If this is a summary posting, the report interval's
|
||||||
-- end date if this is the first summary posting in
|
-- end date if this is the first summary posting in
|
||||||
-- the interval.
|
-- the interval.
|
||||||
,Maybe String -- The posting's transaction's description, if this is the first posting in the transaction.
|
,Maybe Text -- The posting's transaction's description, if this is the first posting in the transaction.
|
||||||
,Posting -- The posting, possibly with the account name depth-clipped.
|
,Posting -- The posting, possibly with the account name depth-clipped.
|
||||||
,MixedAmount -- The running total after this posting, or with --average,
|
,MixedAmount -- The running total after this posting, or with --average,
|
||||||
-- the running average posting amount. With --historical,
|
-- the running average posting amount. With --historical,
|
||||||
@ -66,8 +63,7 @@ type SummaryPosting = (Posting, Day)
|
|||||||
-- | Select postings from the journal and add running balance and other
|
-- | Select postings from the journal and add running balance and other
|
||||||
-- information to make a postings report. Used by eg hledger's register command.
|
-- information to make a postings report. Used by eg hledger's register command.
|
||||||
postingsReport :: ReportSpec -> Journal -> PostingsReport
|
postingsReport :: ReportSpec -> Journal -> PostingsReport
|
||||||
postingsReport rspec@ReportSpec{rsOpts=ropts@ReportOpts{..}} j =
|
postingsReport rspec@ReportSpec{rsOpts=ropts@ReportOpts{..}} j = items
|
||||||
(totallabel, items)
|
|
||||||
where
|
where
|
||||||
reportspan = adjustReportDates rspec j
|
reportspan = adjustReportDates rspec j
|
||||||
whichdate = whichDateFromOpts ropts
|
whichdate = whichDateFromOpts ropts
|
||||||
@ -130,8 +126,6 @@ registerRunningCalculationFn ropts
|
|||||||
| average_ ropts = \i avg amt -> avg + divideMixedAmount (fromIntegral i) (amt - avg)
|
| average_ ropts = \i avg amt -> avg + divideMixedAmount (fromIntegral i) (amt - avg)
|
||||||
| otherwise = \_ bal amt -> bal + amt
|
| otherwise = \_ bal amt -> bal + amt
|
||||||
|
|
||||||
totallabel = "Total"
|
|
||||||
|
|
||||||
-- | Adjust report start/end dates to more useful ones based on
|
-- | Adjust report start/end dates to more useful ones based on
|
||||||
-- journal data and report intervals. Ie:
|
-- journal data and report intervals. Ie:
|
||||||
-- 1. If the start date is unspecified, use the earliest date in the journal (if any)
|
-- 1. If the start date is unspecified, use the earliest date in the journal (if any)
|
||||||
@ -206,14 +200,13 @@ mkpostingsReportItem :: Bool -> Bool -> WhichDate -> Maybe Day -> Posting -> Mix
|
|||||||
mkpostingsReportItem showdate showdesc wd menddate p b =
|
mkpostingsReportItem showdate showdesc wd menddate p b =
|
||||||
(if showdate then Just date else Nothing
|
(if showdate then Just date else Nothing
|
||||||
,menddate
|
,menddate
|
||||||
,if showdesc then Just desc else Nothing
|
,if showdesc then tdescription <$> ptransaction p else Nothing
|
||||||
,p
|
,p
|
||||||
,b
|
,b
|
||||||
)
|
)
|
||||||
where
|
where
|
||||||
date = case wd of PrimaryDate -> postingDate p
|
date = case wd of PrimaryDate -> postingDate p
|
||||||
SecondaryDate -> postingDate2 p
|
SecondaryDate -> postingDate2 p
|
||||||
desc = T.unpack $ maybe "" tdescription $ ptransaction p
|
|
||||||
|
|
||||||
-- | Convert a list of postings into summary postings, one per interval,
|
-- | Convert a list of postings into summary postings, one per interval,
|
||||||
-- aggregated to the specified depth if any.
|
-- aggregated to the specified depth if any.
|
||||||
@ -267,7 +260,7 @@ negatePostingAmount p = p { pamount = negate $ pamount p }
|
|||||||
tests_PostingsReport = tests "PostingsReport" [
|
tests_PostingsReport = tests "PostingsReport" [
|
||||||
|
|
||||||
test "postingsReport" $ do
|
test "postingsReport" $ do
|
||||||
let (query, journal) `gives` n = (length $ snd $ postingsReport defreportspec{rsQuery=query} journal) @?= n
|
let (query, journal) `gives` n = (length $ postingsReport defreportspec{rsQuery=query} journal) @?= n
|
||||||
-- with the query specified explicitly
|
-- with the query specified explicitly
|
||||||
(Any, nulljournal) `gives` 0
|
(Any, nulljournal) `gives` 0
|
||||||
(Any, samplejournal) `gives` 13
|
(Any, samplejournal) `gives` 13
|
||||||
@ -276,10 +269,10 @@ tests_PostingsReport = tests "PostingsReport" [
|
|||||||
(And [Depth 1, StatusQ Cleared, Acct (toRegex' "expenses")], samplejournal) `gives` 2
|
(And [Depth 1, StatusQ Cleared, Acct (toRegex' "expenses")], samplejournal) `gives` 2
|
||||||
(And [And [Depth 1, StatusQ Cleared], Acct (toRegex' "expenses")], samplejournal) `gives` 2
|
(And [And [Depth 1, StatusQ Cleared], Acct (toRegex' "expenses")], samplejournal) `gives` 2
|
||||||
-- with query and/or command-line options
|
-- with query and/or command-line options
|
||||||
(length $ snd $ postingsReport defreportspec samplejournal) @?= 13
|
(length $ postingsReport defreportspec samplejournal) @?= 13
|
||||||
(length $ snd $ postingsReport defreportspec{rsOpts=defreportopts{interval_=Months 1}} samplejournal) @?= 11
|
(length $ postingsReport defreportspec{rsOpts=defreportopts{interval_=Months 1}} samplejournal) @?= 11
|
||||||
(length $ snd $ postingsReport defreportspec{rsOpts=defreportopts{interval_=Months 1, empty_=True}} samplejournal) @?= 20
|
(length $ postingsReport defreportspec{rsOpts=defreportopts{interval_=Months 1, empty_=True}} samplejournal) @?= 20
|
||||||
(length $ snd $ postingsReport defreportspec{rsQuery=Acct $ toRegex' "assets:bank:checking"} samplejournal) @?= 5
|
(length $ postingsReport defreportspec{rsQuery=Acct $ toRegex' "assets:bank:checking"} samplejournal) @?= 5
|
||||||
|
|
||||||
-- (defreportopts, And [Acct "a a", Acct "'b"], samplejournal2) `gives` 0
|
-- (defreportopts, And [Acct "a a", Acct "'b"], samplejournal2) `gives` 0
|
||||||
-- [(Just (fromGregorian 2008 01 01,"income"),assets:bank:checking $1,$1)
|
-- [(Just (fromGregorian 2008 01 01,"income"),assets:bank:checking $1,$1)
|
||||||
|
@ -30,6 +30,8 @@ import qualified Data.Set as S
|
|||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.Lazy as TL
|
||||||
|
import qualified Data.Text.Lazy.IO as TL
|
||||||
import Data.Time.Calendar (Day)
|
import Data.Time.Calendar (Day)
|
||||||
import Data.Time.Format (formatTime, defaultTimeLocale, iso8601DateFormat)
|
import Data.Time.Format (formatTime, defaultTimeLocale, iso8601DateFormat)
|
||||||
import Safe (headDef, headMay, atMay)
|
import Safe (headDef, headMay, atMay)
|
||||||
@ -442,7 +444,7 @@ journalAddTransaction j@Journal{jtxns=ts} opts t = do
|
|||||||
-- unelided shows all amounts explicitly, in case there's a price, cf #283
|
-- unelided shows all amounts explicitly, in case there's a price, cf #283
|
||||||
when (debug_ opts > 0) $ do
|
when (debug_ opts > 0) $ do
|
||||||
putStrLn $ printf "\nAdded transaction to %s:" f
|
putStrLn $ printf "\nAdded transaction to %s:" f
|
||||||
putStrLn =<< registerFromString (showTransaction t)
|
TL.putStrLn =<< registerFromString (T.pack $ showTransaction t)
|
||||||
return j{jtxns=ts++[t]}
|
return j{jtxns=ts++[t]}
|
||||||
|
|
||||||
-- | Append a string, typically one or more transactions, to a journal
|
-- | Append a string, typically one or more transactions, to a journal
|
||||||
@ -464,9 +466,9 @@ ensureOneNewlineTerminated :: String -> String
|
|||||||
ensureOneNewlineTerminated = (++"\n") . reverse . dropWhile (=='\n') . reverse
|
ensureOneNewlineTerminated = (++"\n") . reverse . dropWhile (=='\n') . reverse
|
||||||
|
|
||||||
-- | Convert a string of journal data into a register report.
|
-- | Convert a string of journal data into a register report.
|
||||||
registerFromString :: String -> IO String
|
registerFromString :: Text -> IO TL.Text
|
||||||
registerFromString s = do
|
registerFromString s = do
|
||||||
j <- readJournal' $ T.pack s
|
j <- readJournal' s
|
||||||
return . postingsReportAsText opts $ postingsReport rspec j
|
return . postingsReportAsText opts $ postingsReport rspec j
|
||||||
where
|
where
|
||||||
ropts = defreportopts{empty_=True}
|
ropts = defreportopts{empty_=True}
|
||||||
|
@ -23,6 +23,7 @@ import Data.Maybe
|
|||||||
-- import Data.Text (Text)
|
-- import Data.Text (Text)
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.Lazy as TL
|
import qualified Data.Text.Lazy as TL
|
||||||
|
import qualified Data.Text.Lazy.Builder as TB
|
||||||
import System.Console.CmdArgs.Explicit
|
import System.Console.CmdArgs.Explicit
|
||||||
import Hledger.Read.CsvReader (CSV, CsvRecord, printCSV)
|
import Hledger.Read.CsvReader (CSV, CsvRecord, printCSV)
|
||||||
|
|
||||||
@ -58,16 +59,17 @@ registermode = hledgerCommandMode
|
|||||||
|
|
||||||
-- | Print a (posting) register report.
|
-- | Print a (posting) register report.
|
||||||
register :: CliOpts -> Journal -> IO ()
|
register :: CliOpts -> Journal -> IO ()
|
||||||
register opts@CliOpts{reportspec_=rspec} j = do
|
register opts@CliOpts{reportspec_=rspec} j =
|
||||||
let fmt = outputFormatFromOpts opts
|
writeOutputLazyText opts . render $ postingsReport rspec j
|
||||||
render | fmt=="txt" = postingsReportAsText
|
where
|
||||||
| fmt=="csv" = const ((++"\n") . printCSV . postingsReportAsCsv)
|
fmt = outputFormatFromOpts opts
|
||||||
| fmt=="json" = const ((++"\n") . TL.unpack . toJsonText)
|
render | fmt=="txt" = postingsReportAsText opts
|
||||||
| otherwise = const $ error' $ unsupportedOutputFormatError fmt -- PARTIAL:
|
| fmt=="csv" = TL.pack . printCSV . postingsReportAsCsv
|
||||||
writeOutput opts . render opts $ postingsReport rspec j
|
| fmt=="json" = toJsonText
|
||||||
|
| otherwise = error' $ unsupportedOutputFormatError fmt -- PARTIAL:
|
||||||
|
|
||||||
postingsReportAsCsv :: PostingsReport -> CSV
|
postingsReportAsCsv :: PostingsReport -> CSV
|
||||||
postingsReportAsCsv (_,is) =
|
postingsReportAsCsv is =
|
||||||
["txnidx","date","code","description","account","amount","total"]
|
["txnidx","date","code","description","account","amount","total"]
|
||||||
:
|
:
|
||||||
map postingsReportItemAsCsvRecord is
|
map postingsReportItemAsCsvRecord is
|
||||||
@ -89,13 +91,17 @@ postingsReportItemAsCsvRecord (_, _, _, p, b) = [idx,date,code,desc,acct,amt,bal
|
|||||||
bal = showMixedAmountOneLineWithoutPrice False b
|
bal = showMixedAmountOneLineWithoutPrice False b
|
||||||
|
|
||||||
-- | Render a register report as plain text suitable for console output.
|
-- | Render a register report as plain text suitable for console output.
|
||||||
postingsReportAsText :: CliOpts -> PostingsReport -> String
|
postingsReportAsText :: CliOpts -> PostingsReport -> TL.Text
|
||||||
postingsReportAsText opts (_,items) = unlines $ map (postingsReportItemAsText opts amtwidth balwidth) items
|
postingsReportAsText opts items =
|
||||||
|
TB.toLazyText . unlinesB $
|
||||||
|
map (postingsReportItemAsText opts amtwidth balwidth) items
|
||||||
where
|
where
|
||||||
amtwidth = maximumStrict $ map (snd . showMixed showAmount (Just 12) Nothing False . itemamt) items
|
amtwidth = maximumStrict $ map (snd . showMixed showAmount (Just 12) Nothing False . itemamt) items
|
||||||
balwidth = maximumStrict $ map (snd . showMixed showAmount (Just 12) Nothing False . itembal) items
|
balwidth = maximumStrict $ map (snd . showMixed showAmount (Just 12) Nothing False . itembal) items
|
||||||
itemamt (_,_,_,Posting{pamount=a},_) = a
|
itemamt (_,_,_,Posting{pamount=a},_) = a
|
||||||
itembal (_,_,_,_,a) = a
|
itembal (_,_,_,_,a) = a
|
||||||
|
unlinesB [] = mempty
|
||||||
|
unlinesB xs = mconcat (intersperse (TB.fromText "\n") xs) <> TB.fromText "\n"
|
||||||
|
|
||||||
-- | Render one register report line item as plain text. Layout is like so:
|
-- | Render one register report line item as plain text. Layout is like so:
|
||||||
-- @
|
-- @
|
||||||
@ -119,36 +125,30 @@ postingsReportAsText opts (_,items) = unlines $ map (postingsReportItemAsText op
|
|||||||
-- has multiple commodities. Does not yet support formatting control
|
-- has multiple commodities. Does not yet support formatting control
|
||||||
-- like balance reports.
|
-- like balance reports.
|
||||||
--
|
--
|
||||||
postingsReportItemAsText :: CliOpts -> Int -> Int -> PostingsReportItem -> String
|
postingsReportItemAsText :: CliOpts -> Int -> Int -> PostingsReportItem -> TB.Builder
|
||||||
postingsReportItemAsText opts preferredamtwidth preferredbalwidth (mdate, menddate, mdesc, p, b) =
|
postingsReportItemAsText opts preferredamtwidth preferredbalwidth (mdate, menddate, mdesc, p, b) =
|
||||||
-- use elide*Width to be wide-char-aware
|
-- use elide*Width to be wide-char-aware
|
||||||
-- trace (show (totalwidth, datewidth, descwidth, acctwidth, amtwidth, balwidth)) $
|
-- trace (show (totalwidth, datewidth, descwidth, acctwidth, amtwidth, balwidth)) $
|
||||||
intercalate "\n" $
|
foldMap mconcat . intersperse ([TB.fromText "\n"]) . map (map TB.fromText) $
|
||||||
concat [fitString (Just datewidth) (Just datewidth) True True date
|
[ fitText (Just datewidth) (Just datewidth) True True date
|
||||||
," "
|
, " "
|
||||||
,fitString (Just descwidth) (Just descwidth) True True desc
|
, fitText (Just descwidth) (Just descwidth) True True desc
|
||||||
," "
|
, " "
|
||||||
,fitString (Just acctwidth) (Just acctwidth) True True acct
|
, fitText (Just acctwidth) (Just acctwidth) True True acct
|
||||||
," "
|
, " "
|
||||||
,amtfirstline
|
, amtfirstline
|
||||||
," "
|
, " "
|
||||||
,balfirstline
|
, balfirstline
|
||||||
]
|
]
|
||||||
:
|
:
|
||||||
[concat [spacer
|
[ [ spacer, a, " ", b ] | (a,b) <- zip amtrest balrest ]
|
||||||
,a
|
|
||||||
," "
|
|
||||||
,b
|
|
||||||
]
|
|
||||||
| (a,b) <- zip amtrest balrest
|
|
||||||
]
|
|
||||||
where
|
where
|
||||||
-- calculate widths
|
-- calculate widths
|
||||||
(totalwidth,mdescwidth) = registerWidthsFromOpts opts
|
(totalwidth,mdescwidth) = registerWidthsFromOpts opts
|
||||||
(datewidth, date) = case (mdate,menddate) of
|
(datewidth, date) = case (mdate,menddate) of
|
||||||
(Just _, Just _) -> (21, showDateSpan (DateSpan mdate menddate))
|
(Just _, Just _) -> (21, T.pack $ showDateSpan (DateSpan mdate menddate))
|
||||||
(Nothing, Just _) -> (21, "")
|
(Nothing, Just _) -> (21, "")
|
||||||
(Just d, Nothing) -> (10, showDate d)
|
(Just d, Nothing) -> (10, T.pack $ showDate d)
|
||||||
_ -> (10, "")
|
_ -> (10, "")
|
||||||
(amtwidth, balwidth)
|
(amtwidth, balwidth)
|
||||||
| shortfall <= 0 = (preferredamtwidth, preferredbalwidth)
|
| shortfall <= 0 = (preferredamtwidth, preferredbalwidth)
|
||||||
@ -171,24 +171,25 @@ postingsReportItemAsText opts preferredamtwidth preferredbalwidth (mdate, mendda
|
|||||||
|
|
||||||
-- gather content
|
-- gather content
|
||||||
desc = fromMaybe "" mdesc
|
desc = fromMaybe "" mdesc
|
||||||
acct = parenthesise $ T.unpack $ elideAccountName awidth $ paccount p
|
acct = parenthesise . elideAccountName awidth $ paccount p
|
||||||
where
|
where
|
||||||
(parenthesise, awidth) =
|
(parenthesise, awidth) =
|
||||||
case ptype p of
|
case ptype p of
|
||||||
BalancedVirtualPosting -> (\s -> "["++s++"]", acctwidth-2)
|
BalancedVirtualPosting -> (\s -> wrap "[" "]" s, acctwidth-2)
|
||||||
VirtualPosting -> (\s -> "("++s++")", acctwidth-2)
|
VirtualPosting -> (\s -> wrap "(" ")" s, acctwidth-2)
|
||||||
_ -> (id,acctwidth)
|
_ -> (id,acctwidth)
|
||||||
amt = fst $ showMixed showAmountWithoutPrice (Just amtwidth) (Just amtwidth) (color_ . rsOpts $ reportspec_ opts) $ pamount p
|
wrap a b x = a <> x <> b
|
||||||
bal = fst $ showMixed showAmountWithoutPrice (Just balwidth) (Just balwidth) (color_ . rsOpts $ reportspec_ opts) b
|
amt = T.pack . fst $ showMixed showAmountWithoutPrice (Just amtwidth) (Just amtwidth) (color_ . rsOpts $ reportspec_ opts) $ pamount p
|
||||||
|
bal = T.pack . fst $ showMixed showAmountWithoutPrice (Just balwidth) (Just balwidth) (color_ . rsOpts $ reportspec_ opts) b
|
||||||
-- alternate behaviour, show null amounts as 0 instead of blank
|
-- alternate behaviour, show null amounts as 0 instead of blank
|
||||||
-- amt = if null amt' then "0" else amt'
|
-- amt = if null amt' then "0" else amt'
|
||||||
-- bal = if null bal' then "0" else bal'
|
-- bal = if null bal' then "0" else bal'
|
||||||
(amtlines, ballines) = (lines amt, lines bal)
|
(amtlines, ballines) = (T.lines amt, T.lines bal)
|
||||||
(amtlen, ballen) = (length amtlines, length ballines)
|
(amtlen, ballen) = (length amtlines, length ballines)
|
||||||
numlines = max 1 (max amtlen ballen)
|
numlines = max 1 (max amtlen ballen)
|
||||||
(amtfirstline:amtrest) = take numlines $ amtlines ++ repeat (replicate amtwidth ' ') -- posting amount is top-aligned
|
(amtfirstline:amtrest) = take numlines $ amtlines ++ repeat (T.replicate amtwidth " ") -- posting amount is top-aligned
|
||||||
(balfirstline:balrest) = take numlines $ replicate (numlines - ballen) (replicate balwidth ' ') ++ ballines -- balance amount is bottom-aligned
|
(balfirstline:balrest) = take numlines $ replicate (numlines - ballen) (T.replicate balwidth " ") ++ ballines -- balance amount is bottom-aligned
|
||||||
spacer = replicate (totalwidth - (amtwidth + 2 + balwidth)) ' '
|
spacer = T.replicate (totalwidth - (amtwidth + 2 + balwidth)) " "
|
||||||
|
|
||||||
-- tests
|
-- tests
|
||||||
|
|
||||||
@ -198,7 +199,7 @@ tests_Register = tests "Register" [
|
|||||||
test "unicode in register layout" $ do
|
test "unicode in register layout" $ do
|
||||||
j <- readJournal' "2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n"
|
j <- readJournal' "2009/01/01 * медвежья шкура\n расходы:покупки 100\n актив:наличные\n"
|
||||||
let rspec = defreportspec
|
let rspec = defreportspec
|
||||||
(postingsReportAsText defcliopts $ postingsReport rspec j)
|
(TL.unpack . postingsReportAsText defcliopts $ postingsReport rspec j)
|
||||||
@?=
|
@?=
|
||||||
unlines
|
unlines
|
||||||
["2009-01-01 медвежья шкура расходы:покупки 100 100"
|
["2009-01-01 медвежья шкура расходы:покупки 100 100"
|
||||||
|
@ -10,6 +10,7 @@ where
|
|||||||
import Data.Char (toUpper)
|
import Data.Char (toUpper)
|
||||||
import Data.List
|
import Data.List
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
|
import qualified Data.Text.Lazy.IO as TL
|
||||||
import Hledger
|
import Hledger
|
||||||
import Hledger.Cli.CliOptions
|
import Hledger.Cli.CliOptions
|
||||||
import Hledger.Cli.Commands.Register
|
import Hledger.Cli.Commands.Register
|
||||||
@ -25,14 +26,13 @@ registermatch :: CliOpts -> Journal -> IO ()
|
|||||||
registermatch opts@CliOpts{rawopts_=rawopts,reportspec_=rspec} j =
|
registermatch opts@CliOpts{rawopts_=rawopts,reportspec_=rspec} j =
|
||||||
case listofstringopt "args" rawopts of
|
case listofstringopt "args" rawopts of
|
||||||
[desc] -> do
|
[desc] -> do
|
||||||
let (_,pris) = postingsReport rspec j
|
let ps = [p | (_,_,_,p,_) <- postingsReport rspec j]
|
||||||
ps = [p | (_,_,_,p,_) <- pris]
|
|
||||||
case similarPosting ps desc of
|
case similarPosting ps desc of
|
||||||
Nothing -> putStrLn "no matches found."
|
Nothing -> putStrLn "no matches found."
|
||||||
Just p -> putStr $ postingsReportAsText opts ("",[pri])
|
Just p -> TL.putStr $ postingsReportAsText opts [pri]
|
||||||
where pri = (Just (postingDate p)
|
where pri = (Just (postingDate p)
|
||||||
,Nothing
|
,Nothing
|
||||||
,Just $ T.unpack (maybe "" tdescription $ ptransaction p)
|
,tdescription <$> ptransaction p
|
||||||
,p
|
,p
|
||||||
,0)
|
,0)
|
||||||
_ -> putStrLn "please provide one description argument."
|
_ -> putStrLn "please provide one description argument."
|
||||||
|
@ -13,6 +13,7 @@ module Hledger.Cli.Utils
|
|||||||
unsupportedOutputFormatError,
|
unsupportedOutputFormatError,
|
||||||
withJournalDo,
|
withJournalDo,
|
||||||
writeOutput,
|
writeOutput,
|
||||||
|
writeOutputLazyText,
|
||||||
journalTransform,
|
journalTransform,
|
||||||
journalAddForecast,
|
journalAddForecast,
|
||||||
journalReload,
|
journalReload,
|
||||||
@ -34,6 +35,8 @@ import Data.List
|
|||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import qualified Data.Text as T
|
import qualified Data.Text as T
|
||||||
import qualified Data.Text.IO as T
|
import qualified Data.Text.IO as T
|
||||||
|
import qualified Data.Text.Lazy as TL
|
||||||
|
import qualified Data.Text.Lazy.IO as TL
|
||||||
import Data.Time (UTCTime, Day, addDays)
|
import Data.Time (UTCTime, Day, addDays)
|
||||||
import Safe (readMay)
|
import Safe (readMay)
|
||||||
import System.Console.CmdArgs
|
import System.Console.CmdArgs
|
||||||
@ -159,6 +162,14 @@ writeOutput opts s = do
|
|||||||
f <- outputFileFromOpts opts
|
f <- outputFileFromOpts opts
|
||||||
(if f == "-" then putStr else writeFile f) s
|
(if f == "-" then putStr else writeFile f) s
|
||||||
|
|
||||||
|
-- | Write some output to stdout or to a file selected by --output-file.
|
||||||
|
-- If the file exists it will be overwritten. This function operates on Lazy
|
||||||
|
-- Text values.
|
||||||
|
writeOutputLazyText :: CliOpts -> TL.Text -> IO ()
|
||||||
|
writeOutputLazyText opts s = do
|
||||||
|
f <- outputFileFromOpts opts
|
||||||
|
(if f == "-" then TL.putStr else TL.writeFile f) s
|
||||||
|
|
||||||
-- -- | Get a journal from the given string and options, or throw an error.
|
-- -- | Get a journal from the given string and options, or throw an error.
|
||||||
-- readJournal :: CliOpts -> String -> IO Journal
|
-- readJournal :: CliOpts -> String -> IO Journal
|
||||||
-- readJournal opts s = readJournal def Nothing s >>= either error' return
|
-- readJournal opts s = readJournal def Nothing s >>= either error' return
|
||||||
|
Loading…
Reference in New Issue
Block a user