hledger-lib 1.18 → 1.18.1
raw patch · 27 files changed
+687/−610 lines, 27 files
Files
- CHANGES.md +4/−0
- Hledger/Data/Journal.hs +12/−12
- Hledger/Data/Types.hs +2/−2
- Hledger/Data/Valuation.hs +149/−134
- Hledger/Read.hs +1/−1
- Hledger/Read/CsvReader.hs +26/−26
- Hledger/Read/JournalReader.hs +3/−3
- Hledger/Reports/AccountTransactionsReport.hs +1/−1
- Hledger/Reports/BalanceReport.hs +23/−18
- Hledger/Reports/EntriesReport.hs +1/−1
- Hledger/Reports/MultiBalanceReport.hs +46/−38
- Hledger/Reports/PostingsReport.hs +1/−1
- Hledger/Reports/ReportOptions.hs +7/−5
- Hledger/Utils/Debug.hs +29/−1
- hledger-lib.cabal +2/−2
- hledger_csv.5 +2/−2
- hledger_csv.info +71/−71
- hledger_csv.txt +2/−2
- hledger_journal.5 +12/−7
- hledger_journal.info +131/−126
- hledger_journal.txt +154/−149
- hledger_timeclock.5 +1/−1
- hledger_timeclock.info +2/−2
- hledger_timeclock.txt +1/−1
- hledger_timedot.5 +1/−1
- hledger_timedot.info +2/−2
- hledger_timedot.txt +1/−1
CHANGES.md view
@@ -1,6 +1,10 @@ Internal/api/developer-ish changes in the hledger-lib (and hledger) packages. For user-visible changes, see the hledger package changelog. +# 1.18.1 2020-06-21++- fix some doc typos (Martin Michlmayr)+ # 1.18 2020-06-07 - added: getHledgerCliOpts', takes an explicit argument list
Hledger/Data/Journal.hs view
@@ -179,18 +179,18 @@ ,jparseparentaccounts = jparseparentaccounts j2 ,jparsealiases = jparsealiases j2 -- ,jparsetransactioncount = jparsetransactioncount j1 + jparsetransactioncount j2- ,jparsetimeclockentries = jparsetimeclockentries j1 <> jparsetimeclockentries j2- ,jincludefilestack = jincludefilestack j2+ ,jparsetimeclockentries = jparsetimeclockentries j1 <> jparsetimeclockentries j2+ ,jincludefilestack = jincludefilestack j2 ,jdeclaredaccounts = jdeclaredaccounts j1 <> jdeclaredaccounts j2 ,jdeclaredaccounttypes = jdeclaredaccounttypes j1 <> jdeclaredaccounttypes j2 ,jcommodities = jcommodities j1 <> jcommodities j2 ,jinferredcommodities = jinferredcommodities j1 <> jinferredcommodities j2- ,jpricedirectives = jpricedirectives j1 <> jpricedirectives j2- ,jtransactionimpliedmarketprices = jtransactionimpliedmarketprices j1 <> jtransactionimpliedmarketprices j2+ ,jpricedirectives = jpricedirectives j1 <> jpricedirectives j2+ ,jinferredmarketprices = jinferredmarketprices j1 <> jinferredmarketprices j2 ,jtxnmodifiers = jtxnmodifiers j1 <> jtxnmodifiers j2 ,jperiodictxns = jperiodictxns j1 <> jperiodictxns j2 ,jtxns = jtxns j1 <> jtxns j2- ,jfinalcommentlines = jfinalcommentlines j2 -- XXX discards j1's ?+ ,jfinalcommentlines = jfinalcommentlines j2 -- XXX discards j1's ? ,jfiles = jfiles j1 <> jfiles j2 ,jlastreadtime = max (jlastreadtime j1) (jlastreadtime j2) }@@ -211,8 +211,8 @@ ,jdeclaredaccounttypes = M.empty ,jcommodities = M.empty ,jinferredcommodities = M.empty- ,jpricedirectives = []- ,jtransactionimpliedmarketprices = []+ ,jpricedirectives = []+ ,jinferredmarketprices = [] ,jtxnmodifiers = [] ,jperiodictxns = [] ,jtxns = []@@ -1044,16 +1044,16 @@ -- been balanced and posting amounts have appropriate prices attached. journalInferMarketPricesFromTransactions :: Journal -> Journal journalInferMarketPricesFromTransactions j =- j{jtransactionimpliedmarketprices =- dbg4 "jtransactionimpliedmarketprices" $- mapMaybe postingImpliedMarketPrice $ journalPostings j+ j{jinferredmarketprices =+ dbg4 "jinferredmarketprices" $+ mapMaybe postingInferredmarketPrice $ journalPostings j } -- | Make a market price equivalent to this posting's amount's unit -- price, if any. If the posting amount is multicommodity, only the -- first commodity amount is considered.-postingImpliedMarketPrice :: Posting -> Maybe MarketPrice-postingImpliedMarketPrice p@Posting{pamount} =+postingInferredmarketPrice :: Posting -> Maybe MarketPrice+postingInferredmarketPrice p@Posting{pamount} = -- convert any total prices to unit prices case mixedAmountTotalPriceToUnitPrice pamount of Mixed ( Amount{acommodity=fromcomm, aprice = Just (UnitPrice Amount{acommodity=tocomm, aquantity=rate})} : _) ->
Hledger/Data/Types.hs view
@@ -470,9 +470,9 @@ ,jdeclaredaccounts :: [(AccountName,AccountDeclarationInfo)] -- ^ Accounts declared by account directives, in parse order (after journal finalisation) ,jdeclaredaccounttypes :: M.Map AccountType [AccountName] -- ^ Accounts whose type has been declared in account directives (usually 5 top-level accounts) ,jcommodities :: M.Map CommoditySymbol Commodity -- ^ commodities and formats declared by commodity directives- ,jinferredcommodities :: M.Map CommoditySymbol AmountStyle -- ^ commodities and formats inferred from journal amounts TODO misnamed - jusedstyles+ ,jinferredcommodities :: M.Map CommoditySymbol AmountStyle -- ^ commodities and formats inferred from journal amounts TODO misnamed, should be eg jusedstyles ,jpricedirectives :: [PriceDirective] -- ^ Declarations of market prices by P directives, in parse order (after journal finalisation)- ,jtransactionimpliedmarketprices :: [MarketPrice] -- ^ Market prices implied by transactions, in parse order (after journal finalisation)+ ,jinferredmarketprices :: [MarketPrice] -- ^ Market prices implied by transactions, in parse order (after journal finalisation) ,jtxnmodifiers :: [TransactionModifier] ,jperiodictxns :: [PeriodicTransaction] ,jtxns :: [Transaction]
Hledger/Data/Valuation.hs view
@@ -52,6 +52,17 @@ ------------------------------------------------------------------------------ -- Types +-- | What kind of value conversion should be done on amounts ?+-- CLI: --value=cost|then|end|now|DATE[,COMM]+data ValuationType =+ AtCost (Maybe CommoditySymbol) -- ^ convert to cost commodity using transaction prices, then optionally to given commodity using market prices at posting date+ | AtThen (Maybe CommoditySymbol) -- ^ convert to default or given valuation commodity, using market prices at each posting's date+ | AtEnd (Maybe CommoditySymbol) -- ^ convert to default or given valuation commodity, using market prices at period end(s)+ | AtNow (Maybe CommoditySymbol) -- ^ convert to default or given valuation commodity, using current market prices+ | AtDate Day (Maybe CommoditySymbol) -- ^ convert to default or given valuation commodity, using market prices on some date+ | AtDefault (Maybe CommoditySymbol) -- ^ works like AtNow in single period reports, like AtEnd in multiperiod reports+ deriving (Show,Data,Eq) -- Typeable+ -- | A snapshot of the known exchange rates between commodity pairs at a given date, -- as a graph allowing fast lookup and path finding, along with some helper data. data PriceGraph = PriceGraph {@@ -60,9 +71,9 @@ -- Node labels are commodities and edge labels are exchange rates, -- which were either: -- declared by P directives,- -- implied by transaction prices,+ -- inferred from transaction prices, -- inferred by reversing a declared rate,- -- or inferred by reversing a transaction-implied rate.+ -- or inferred by reversing a transaction-inferred rate. -- There will be at most one edge between each directed pair of commodities, -- eg there can be one USD->EUR and one EUR->USD. ,prNodemap :: NodeMap CommoditySymbol@@ -71,7 +82,7 @@ -- ^ The default valuation commodity for each source commodity. -- These are used when a valuation commodity is not specified -- (-V). They are the destination commodity of the latest- -- (declared or transaction-implied, but not reverse) each+ -- (declared or inferred, but not reverse) each -- source commodity's latest market price (on the date of this -- graph). }@@ -79,25 +90,38 @@ instance NFData PriceGraph --- | A price oracle is a magic function that looks up market prices--- (exchange rates) from one commodity to another (or if unspecified,--- to a default valuation commodity) on a given date, somewhat efficiently.+-- | A price oracle is a magic memoising function that efficiently+-- looks up market prices (exchange rates) from one commodity to+-- another (or if unspecified, to a default valuation commodity) on a+-- given date. type PriceOracle = (Day, CommoditySymbol, Maybe CommoditySymbol) -> Maybe (CommoditySymbol, Quantity) --- | What kind of value conversion should be done on amounts ?--- CLI: --value=cost|then|end|now|DATE[,COMM]-data ValuationType =- AtCost (Maybe CommoditySymbol) -- ^ convert to cost commodity using transaction prices, then optionally to given commodity using market prices at posting date- | AtThen (Maybe CommoditySymbol) -- ^ convert to default or given valuation commodity, using market prices at each posting's date- | AtEnd (Maybe CommoditySymbol) -- ^ convert to default or given valuation commodity, using market prices at period end(s)- | AtNow (Maybe CommoditySymbol) -- ^ convert to default or given valuation commodity, using current market prices- | AtDate Day (Maybe CommoditySymbol) -- ^ convert to default or given valuation commodity, using market prices on some date- | AtDefault (Maybe CommoditySymbol) -- ^ works like AtNow in single period reports, like AtEnd in multiperiod reports- deriving (Show,Data,Eq) -- Typeable+-- | Generate a price oracle (memoising price lookup function) from a+-- journal's directive-declared and transaction-inferred market+-- prices. For best performance, generate this only once per journal,+-- reusing it across reports if there are more than one, as+-- compoundBalanceCommand does.+-- The boolean argument is whether to infer market prices from+-- transactions or not.+journalPriceOracle :: Bool -> Journal -> PriceOracle+journalPriceOracle infer Journal{jpricedirectives, jinferredmarketprices} =+ let+ declaredprices = map priceDirectiveToMarketPrice jpricedirectives+ inferredprices = if infer then jinferredmarketprices else []+ makepricegraph = memo $ makePriceGraph declaredprices inferredprices+ in+ memo $ uncurry3 $ priceLookup makepricegraph +priceDirectiveToMarketPrice :: PriceDirective -> MarketPrice+priceDirectiveToMarketPrice PriceDirective{..} =+ MarketPrice{ mpdate = pddate+ , mpfrom = pdcommodity+ , mpto = acommodity pdamount+ , mprate = aquantity pdamount+ } --------------------------------------------------------------------------------- Valuation+-- Converting things to value -- | Apply a specified valuation to this mixed amount, using the -- provided price oracle, commodity styles, reference dates, and@@ -135,8 +159,8 @@ -- use postingApplyValuation for that. -- -- This is all a bit complicated. See the reference doc at--- https://hledger.org/hledger.html#effect-of-value-on-reports--- (hledger_options.m4.md "Effect of --value on reports"), and #1083.+-- https://hledger.org/hledger.html#effect-of-valuation-on-reports+-- (hledger_options.m4.md "Effect of valuation on reports"), and #1083. -- amountApplyValuation :: PriceOracle -> M.Map CommoditySymbol AmountStyle -> Day -> Maybe Day -> Day -> Bool -> ValuationType -> Amount -> Amount amountApplyValuation priceoracle styles periodlast mreportlast today ismultiperiod v a =@@ -189,76 +213,33 @@ ------------------------------------------------------------------------------ -- Market price lookup --- From a journal's directive-declared and transaction-implied market--- prices, generate a memoising function that efficiently looks up--- exchange rates between commodities on any date. For best performance,--- you should generate this only once per journal, reusing it across--- reports if there are more than one (as in compoundBalanceCommand).-journalPriceOracle :: Journal -> PriceOracle-journalPriceOracle Journal{jpricedirectives, jtransactionimpliedmarketprices} =- -- traceStack "journalPriceOracle" $- let- pricesatdate =- memo $- pricesAtDate jpricedirectives jtransactionimpliedmarketprices- in- memo $- uncurry3 $- priceLookup pricesatdate---- | Given a list of price directives in parse order, find the market--- value at the given date of one unit of a given source commodity, in--- a different specified valuation commodity, or a default valuation--- commodity.------ When the valuation commodity is specified, this looks for an--- exchange rate (market price) calculated in any of the following--- ways, in order of preference:------ 1. a declared market price (DMP) - a P directive giving the--- exchange rate from source commodity to valuation commodity------ 2. a transaction-implied market price (TMP) - a market price--- equivalent to the transaction price used in the latest--- transaction from source commodity to valuation commodity--- (on or before the valuation date)------ 3. a reverse declared market price (RDMP) - calculated by inverting--- a DMP------ 4. a reverse transaction-implied market price (RTMP) - calculated--- by inverting a TMP------ 5. an indirect market price (IMP) - calculated by combining the--- shortest chain of market prices (any of the above types) leading--- from source commodity to valuation commodity.------ When the valuation commodity is not specified, this looks for the--- latest applicable declared or transaction-implied price, and--- converts to the commodity mentioned in that price (the default--- valuation commodity).------ Note this default valuation commodity can vary across successive--- calls for different dates, since it depends on the price--- declarations in each period.+-- | Given a memoising price graph generator, a valuation date, a+-- source commodity and an optional valuation commodity, find the+-- value on that date of one unit of the source commodity in the+-- valuation commodity, or in a default valuation commodity. Returns+-- the valuation commodity that was specified or chosen, and the+-- quantity of it that one unit of the source commodity is worth. Or+-- if no applicable market price can be found or calculated, or if the+-- source commodity and the valuation commodity are the same, returns+-- Nothing. ----- This returns the valuation commodity that was specified or--- inferred, and the quantity of it that one unit of the source--- commodity is worth. Or if no applicable market price or chain of--- prices can be found, or the source commodity and the valuation--- commodity are the same, returns Nothing.+-- See makePriceGraph for how prices are determined.+-- Note that both market prices and default valuation commodities can+-- vary with valuation date, since that determines which market prices+-- are visible. -- priceLookup :: (Day -> PriceGraph) -> Day -> CommoditySymbol -> Maybe CommoditySymbol -> Maybe (CommoditySymbol, Quantity)-priceLookup pricesatdate d from mto =+priceLookup makepricegraph d from mto = -- trace ("priceLookup ("++show d++", "++show from++", "++show mto++")") $ let -- build a graph of the commodity exchange rates in effect on this day -- XXX should hide these fgl details better- PriceGraph{prGraph=g, prNodemap=m, prDefaultValuationCommodities=defaultdests} = pricesatdate d+ PriceGraph{prGraph=g, prNodemap=m, prDefaultValuationCommodities=defaultdests} =+ traceAt 1 ("valuation date: "++show d) $ makepricegraph d fromnode = node m from mto' = mto <|> mdefaultto where- mdefaultto = dbg4 ("default valuation commodity for "++T.unpack from) $+ mdefaultto = dbg1 ("default valuation commodity for "++T.unpack from) $ M.lookup from defaultdests in case mto' of@@ -276,18 +257,17 @@ case sp fromnode tonode g :: Maybe [Node] of Nothing -> Nothing Just nodes ->- dbg ("market price "++intercalate "->" (map T.unpack comms)) $+ dbg ("market price for "++intercalate " -> " (map T.unpack comms)) $ Just $ product $ pathEdgeLabels g nodes -- convert to a single exchange rate where comms = catMaybes $ map (lab g) nodes -- log a message and a Maybe Quantity, hiding Just/Nothing and limiting decimal places- dbg msg = dbg4With (((msg++": ")++) . maybe "" (show . roundTo 8))+ dbg msg = dbg1With (((msg++": ")++) . maybe "" (show . roundTo 8)) tests_priceLookup = let d = parsedate- a q c = amount{acommodity=c, aquantity=q}- p date from q to = PriceDirective{pddate=d date, pdcommodity=from, pdamount=a q to}+ p date from q to = MarketPrice{mpdate=d date, mpfrom=from, mpto=to, mprate=q} ps1 = [ p "2000/01/01" "A" 10 "B" ,p "2000/01/01" "B" 10 "C"@@ -295,78 +275,113 @@ ,p "2000/01/01" "E" 2 "D" ,p "2001/01/01" "A" 11 "B" ]- pricesatdate = pricesAtDate ps1 []+ makepricegraph = makePriceGraph ps1 [] in test "priceLookup" $ do- priceLookup pricesatdate (d "1999/01/01") "A" Nothing @?= Nothing- priceLookup pricesatdate (d "2000/01/01") "A" Nothing @?= Just ("B",10)- priceLookup pricesatdate (d "2000/01/01") "B" (Just "A") @?= Just ("A",0.1)- priceLookup pricesatdate (d "2000/01/01") "A" (Just "E") @?= Just ("E",500)----------------------------------------------------------------------------------- Building the price graph (network of commodity conversions) on a given day.+ priceLookup makepricegraph (d "1999/01/01") "A" Nothing @?= Nothing+ priceLookup makepricegraph (d "2000/01/01") "A" Nothing @?= Just ("B",10)+ priceLookup makepricegraph (d "2000/01/01") "B" (Just "A") @?= Just ("A",0.1)+ priceLookup makepricegraph (d "2000/01/01") "A" (Just "E") @?= Just ("E",500) --- | Convert a list of market price directives in parse order, and a--- list of transaction-implied market prices in parse order, to a--- graph of the effective exchange rates between commodity pairs on--- the given day.-pricesAtDate :: [PriceDirective] -> [MarketPrice] -> Day -> PriceGraph-pricesAtDate pricedirectives transactionimpliedmarketprices d =- -- trace ("pricesAtDate ("++show d++")") $+-- | Build the graph of commodity conversion prices for a given day.+-- Converts a list of declared market prices in parse order, and a+-- list of transaction-inferred market prices in parse order, to a+-- graph of all known exchange rates between commodity pairs in effect+-- on that day. Cf hledger.m4.md -> Valuation:+--+-- hledger looks for a market price (exchange rate) from commodity A+-- to commodity B in one or more of these ways, in this order of+-- preference:+--+-- 1. A *declared market price* or *inferred market price*:+-- A's latest market price in B on or before the valuation date+-- as declared by a P directive, or (with the `--infer-value` flag)+-- inferred from transaction prices.+-- +-- 2. A *reverse market price*:+-- the inverse of a declared or inferred market price from B to A.+-- +-- 3. A *chained market price*:+-- a synthetic price formed by combining the shortest chain of market+-- prices (any of the above types) leading from A to B.+--+-- 1 and 2 form the edges of the price graph, and we can query it for+-- 3 (which is the reason we use a graph).+--+-- We also identify each commodity's default valuation commodity, if+-- any. For each commodity A, hledger picks a default valuation+-- commodity as follows, in this order of preference:+--+-- 1. The price commodity from the latest declared market price for A+-- on or before valuation date.+--+-- 2. The price commodity from the latest declared market price for A+-- on any date. (Allows conversion to proceed if there are inferred+-- prices before the valuation date.)+--+-- 3. If there are no P directives at all (any commodity or date), and+-- the `--infer-value` flag is used, then the price commodity from+-- the latest transaction price for A on or before valuation date.+--+makePriceGraph :: [MarketPrice] -> [MarketPrice] -> Day -> PriceGraph+makePriceGraph alldeclaredprices allinferredprices d =+ dbg9 ("makePriceGraph "++show d) $ PriceGraph{prGraph=g, prNodemap=m, prDefaultValuationCommodities=defaultdests} where- declaredandimpliedprices = latestPriceForEachPairOn pricedirectives transactionimpliedmarketprices d+ -- prices in effect on date d, either declared or inferred+ visibledeclaredprices = filter ((<=d).mpdate) alldeclaredprices+ visibleinferredprices = filter ((<=d).mpdate) allinferredprices+ declaredandinferredprices = dbg2 "declaredandinferredprices" $+ effectiveMarketPrices visibledeclaredprices visibleinferredprices - -- infer any additional reverse prices not already declared or implied- reverseprices =- dbg5 "reverseprices" $- map marketPriceReverse declaredandimpliedprices \\ declaredandimpliedprices+ -- infer any additional reverse prices not already declared or inferred+ reverseprices = dbg2 "reverseprices" $+ map marketPriceReverse declaredandinferredprices \\ declaredandinferredprices -- build the graph and associated node map (g, m) = mkMapGraph- (dbg5 "g nodelabels" $ sort allcomms) -- this must include all nodes mentioned in edges- (dbg5 "g edges" $ [(mpfrom, mpto, mprate) | MarketPrice{..} <- prices])+ (dbg9 "price graph labels" $ sort allcomms) -- this must include all nodes mentioned in edges+ (dbg9 "price graph edges" $ [(mpfrom, mpto, mprate) | MarketPrice{..} <- prices]) :: (Gr CommoditySymbol Quantity, NodeMap CommoditySymbol) where- prices = declaredandimpliedprices ++ reverseprices+ prices = declaredandinferredprices ++ reverseprices allcomms = map mpfrom prices - -- save the forward prices' destinations as the default valuation- -- commodity for those source commodities- defaultdests = M.fromList [(mpfrom,mpto) | MarketPrice{..} <- declaredandimpliedprices]+ -- determine a default valuation commodity for each source commodity+ -- somewhat but not quite like effectiveMarketPrices+ defaultdests = M.fromList [(mpfrom,mpto) | MarketPrice{..} <- pricesfordefaultcomms]+ where+ pricesfordefaultcomms = dbg2 "prices for choosing default valuation commodities, by date then parse order" $+ ps+ & zip [1..] -- label items with their parse order+ & sortBy (compare `on` (\(parseorder,MarketPrice{..})->(mpdate,parseorder))) -- sort by increasing date then increasing parse order+ & map snd -- discard labels+ where+ ps | not $ null visibledeclaredprices = visibledeclaredprices+ | not $ null alldeclaredprices = alldeclaredprices+ | otherwise = visibleinferredprices -- will be null without --infer-value --- From a list of price directives in parse order, and a list of--- transaction-implied market prices in parse order, get the effective--- price on the given date for each commodity pair. That is, the--- latest declared or transaction-implied price dated on or before--- that day, with declared prices taking precedence.-latestPriceForEachPairOn :: [PriceDirective] -> [MarketPrice] -> Day -> [MarketPrice]-latestPriceForEachPairOn pricedirectives transactionimpliedmarketprices d =- dbg5 "latestPriceForEachPairOn" $+-- | Given a list of P-declared market prices in parse order and a+-- list of transaction-inferred market prices in parse order, select+-- just the latest prices that are in effect for each commodity pair.+-- That is, for each commodity pair, the latest price by date then+-- parse order, with declared prices having precedence over inferred+-- prices on the same day.+effectiveMarketPrices :: [MarketPrice] -> [MarketPrice] -> [MarketPrice]+effectiveMarketPrices declaredprices inferredprices = let- -- consider only declarations/transactions before the valuation date- declaredprices = map priceDirectiveToMarketPrice $ filter ((<=d).pddate) pricedirectives- transactionimpliedmarketprices' = filter ((<=d).mpdate) transactionimpliedmarketprices- -- label the items with their precedence and then their parse order- declaredprices' = [(1, i, p) | (i,p) <- zip [1..] declaredprices]- transactionimpliedmarketprices'' = [(0, i, p) | (i,p) <- zip [1..] transactionimpliedmarketprices']+ -- label each item with its same-day precedence, then parse order+ declaredprices' = [(1, i, p) | (i,p) <- zip [1..] declaredprices]+ inferredprices' = [(0, i, p) | (i,p) <- zip [1..] inferredprices] in -- combine- declaredprices' ++ transactionimpliedmarketprices''- -- sort by newest date then highest precedence then latest parse order+ declaredprices' ++ inferredprices'+ -- sort by decreasing date then decreasing precedence then decreasing parse order & sortBy (flip compare `on` (\(precedence,parseorder,mp)->(mpdate mp,precedence,parseorder))) -- discard the sorting labels & map third3- -- keep only the first (ie the newest, highest precedence and latest parsed) price for each pair+ -- keep only the first (ie the newest, highest precedence, latest parsed) price for each pair & nubSortBy (compare `on` (\(MarketPrice{..})->(mpfrom,mpto)))--priceDirectiveToMarketPrice :: PriceDirective -> MarketPrice-priceDirectiveToMarketPrice PriceDirective{..} =- MarketPrice{ mpdate = pddate- , mpfrom = pdcommodity- , mpto = acommodity pdamount- , mprate = aquantity pdamount- } marketPriceReverse :: MarketPrice -> MarketPrice marketPriceReverse mp@MarketPrice{..} = mp{mpfrom=mpto, mpto=mpfrom, mprate=1/mprate}
Hledger/Read.hs view
@@ -111,7 +111,7 @@ readJournal iopts mpath txt = do let r :: Reader IO = fromMaybe JournalReader.reader $ findReader (mformat_ iopts) mpath- dbg1IO "trying reader" (rFormat r)+ dbg7IO "trying reader" (rFormat r) (runExceptT . (rReadFn r) iopts (fromMaybe "(string)" mpath)) txt -- | Read the default journal file specified by the environment, or raise an error.
Hledger/Read/CsvReader.hs view
@@ -382,7 +382,7 @@ } blankorcommentlinep :: CsvRulesParser ()-blankorcommentlinep = lift (dbgparse 3 "trying blankorcommentlinep") >> choiceInState [blanklinep, commentlinep]+blankorcommentlinep = lift (dbgparse 8 "trying blankorcommentlinep") >> choiceInState [blanklinep, commentlinep] blanklinep :: CsvRulesParser () blanklinep = lift (skipMany spacenonewline) >> newline >> return () <?> "blank line"@@ -395,7 +395,7 @@ directivep :: CsvRulesParser (DirectiveName, String) directivep = (do- lift $ dbgparse 3 "trying directive"+ lift $ dbgparse 8 "trying directive" d <- fmap T.unpack $ choiceInState $ map (lift . string . T.pack) directives v <- (((char ':' >> lift (many spacenonewline)) <|> lift (some spacenonewline)) >> directivevalp) <|> (optional (char ':') >> lift (skipMany spacenonewline) >> lift eolof >> return "")@@ -418,7 +418,7 @@ fieldnamelistp :: CsvRulesParser [CsvFieldName] fieldnamelistp = (do- lift $ dbgparse 3 "trying fieldnamelist"+ lift $ dbgparse 8 "trying fieldnamelist" string "fields" optional $ char ':' lift (skipSome spacenonewline)@@ -444,7 +444,7 @@ fieldassignmentp :: CsvRulesParser (HledgerFieldName, FieldTemplate) fieldassignmentp = do- lift $ dbgparse 3 "trying fieldassignmentp"+ lift $ dbgparse 8 "trying fieldassignmentp" f <- journalfieldnamep v <- choiceInState [ assignmentseparatorp >> fieldvalp , lift eolof >> return ""@@ -454,7 +454,7 @@ journalfieldnamep :: CsvRulesParser String journalfieldnamep = do- lift (dbgparse 2 "trying journalfieldnamep")+ lift (dbgparse 8 "trying journalfieldnamep") T.unpack <$> choiceInState (map (lift . string . T.pack) journalfieldnames) maxpostings = 99@@ -489,7 +489,7 @@ assignmentseparatorp :: CsvRulesParser () assignmentseparatorp = do- lift $ dbgparse 3 "trying assignmentseparatorp"+ lift $ dbgparse 8 "trying assignmentseparatorp" _ <- choiceInState [ lift (skipMany spacenonewline) >> char ':' >> lift (skipMany spacenonewline) , lift (skipSome spacenonewline) ]@@ -497,13 +497,13 @@ fieldvalp :: CsvRulesParser String fieldvalp = do- lift $ dbgparse 2 "trying fieldvalp"+ lift $ dbgparse 8 "trying fieldvalp" anySingle `manyTill` lift eolof -- A conditional block: one or more matchers, one per line, followed by one or more indented rules. conditionalblockp :: CsvRulesParser ConditionalBlock conditionalblockp = do- lift $ dbgparse 3 "trying conditionalblockp"+ lift $ dbgparse 8 "trying conditionalblockp" string "if" >> lift (skipMany spacenonewline) >> optional newline ms <- some matcherp as <- many (try $ lift (skipSome spacenonewline) >> fieldassignmentp)@@ -520,7 +520,7 @@ -- A pattern on the whole line, not beginning with a csv field reference. recordmatcherp :: CsvRulesParser Matcher recordmatcherp = do- lift $ dbgparse 2 "trying matcherp"+ lift $ dbgparse 8 "trying matcherp" -- pos <- currentPos -- _ <- optional (matchoperatorp >> lift (skipMany spacenonewline) >> optional newline) r <- regexp@@ -535,7 +535,7 @@ -- %description chez jacques fieldmatcherp :: CsvRulesParser Matcher fieldmatcherp = do- lift $ dbgparse 2 "trying fieldmatcher"+ lift $ dbgparse 8 "trying fieldmatcher" -- An optional fieldname (default: "all") -- f <- fromMaybe "all" `fmap` (optional $ do -- f' <- fieldnamep@@ -551,7 +551,7 @@ csvfieldreferencep :: CsvRulesParser CsvFieldReference csvfieldreferencep = do- lift $ dbgparse 3 "trying csvfieldreferencep"+ lift $ dbgparse 8 "trying csvfieldreferencep" char '%' f <- fieldnamep return $ '%' : quoteIfNeeded f@@ -559,7 +559,7 @@ -- A single regular expression regexp :: CsvRulesParser RegexpPattern regexp = do- lift $ dbgparse 3 "trying regexp"+ lift $ dbgparse 8 "trying regexp" -- notFollowedBy matchoperatorp c <- lift nonspace cs <- anySingle `manyTill` lift eolof@@ -606,12 +606,12 @@ rulestext <- if rulesfileexists then do- dbg1IO "using conversion rules file" rulesfile+ dbg7IO "using conversion rules file" rulesfile readFilePortably rulesfile >>= expandIncludes (takeDirectory rulesfile) else return $ defaultRulesText rulesfile rules <- either throwerr return $ parseAndValidateCsvRules rulesfile rulestext- dbg2IO "rules" rules+ dbg7IO "rules" rules -- parse the skip directive's value, if any let skiplines = case getDirective "skip" rules of@@ -623,12 +623,12 @@ -- parsec seems to fail if you pass it "-" here TODO: try again with megaparsec let parsecfilename = if csvfile == "-" then "(stdin)" else csvfile let separator = fromMaybe ',' (getDirective "separator" rules >>= parseSeparator)- dbg2IO "separator" separator+ dbg7IO "separator" separator records <- (either throwerr id .- dbg2 "validateCsv" . validateCsv rules skiplines .- dbg2 "parseCsv")+ dbg8 "validateCsv" . validateCsv rules skiplines .+ dbg8 "parseCsv") `fmap` parseCsv separator parsecfilename csvdata- dbg1IO "first 3 csv records" $ take 3 records+ dbg7IO "first 3 csv records" $ take 3 records -- identify header lines -- let (headerlines, datalines) = identifyHeaderLines records@@ -653,10 +653,10 @@ -- than one date and the first date is more recent than the last): -- reverse them to get same-date transactions ordered chronologically. txns' =- (if newestfirst || mseemsnewestfirst == Just True then reverse else id) txns+ (if newestfirst || mdataseemsnewestfirst == Just True then reverse else id) txns where- newestfirst = dbg3 "newestfirst" $ isJust $ getDirective "newest-first" rules- mseemsnewestfirst = dbg3 "mseemsnewestfirst" $+ newestfirst = dbg7 "newestfirst" $ isJust $ getDirective "newest-first" rules+ mdataseemsnewestfirst = dbg7 "mdataseemsnewestfirst" $ case nub $ map tdate txns of ds | length ds > 1 -> Just $ head ds > last ds _ -> Nothing@@ -1060,7 +1060,7 @@ getEffectiveAssignment rules record f = lastMay $ map snd $ assignments where -- all active assignments to field f, in order- assignments = dbg2 "assignments" $ filter ((==f).fst) $ toplevelassignments ++ conditionalassignments+ assignments = dbg8 "assignments" $ filter ((==f).fst) $ toplevelassignments ++ conditionalassignments where -- all top level field assignments toplevelassignments = rassignments rules@@ -1077,20 +1077,20 @@ matcherMatches :: Matcher -> Bool matcherMatches (RecordMatcher pat) = regexMatchesCI pat' wholecsvline where- pat' = dbg3 "regex" pat+ pat' = dbg8 "regex" pat -- A synthetic whole CSV record to match against. Note, this can be -- different from the original CSV data: -- - any whitespace surrounding field values is preserved -- - any quotes enclosing field values are removed -- - and the field separator is always comma -- which means that a field containing a comma will look like two fields.- wholecsvline = dbg3 "wholecsvline" $ intercalate "," record+ wholecsvline = dbg8 "wholecsvline" $ intercalate "," record matcherMatches (FieldMatcher csvfieldref pat) = regexMatchesCI pat csvfieldvalue where -- the value of the referenced CSV field to match against.- csvfieldvalue = dbg3 "csvfieldvalue" $ replaceCsvFieldReference rules record csvfieldref+ csvfieldvalue = dbg8 "csvfieldvalue" $ replaceCsvFieldReference rules record csvfieldref --- | Render a field assigment's template, possibly interpolating referenced+-- | Render a field assignment's template, possibly interpolating referenced -- CSV field values. Outer whitespace is removed from interpolated values. renderTemplate :: CsvRules -> CsvRecord -> FieldTemplate -> String renderTemplate rules record t = regexReplaceBy "%[A-z0-9_-]+" (replaceCsvFieldReference rules record) t
Hledger/Read/JournalReader.hs view
@@ -296,7 +296,7 @@ -- on journal. Duplicating readJournal a bit here. let r = fromMaybe reader $ findReader Nothing (Just prefixedpath) parser = rParser r- dbg1IO "trying reader" (rFormat r)+ dbg7IO "trying reader" (rFormat r) updatedChildj <- journalAddFile (filepath, childInput) <$> parseIncludeFile parser initChildj filepath childInput @@ -425,7 +425,7 @@ pure $ (off, amount) lift (skipMany spacenonewline) _ <- lift followingcommentp- let comm = Commodity{csymbol=acommodity, cformat=Just $ dbg2 "style from commodity directive" astyle}+ let comm = Commodity{csymbol=acommodity, cformat=Just $ dbg7 "style from commodity directive" astyle} if asdecimalpoint astyle == Nothing then customFailure $ parseErrorAt off pleaseincludedecimalpoint else modify' (\j -> j{jcommodities=M.insert acommodity comm $ jcommodities j})@@ -469,7 +469,7 @@ then if asdecimalpoint astyle == Nothing then customFailure $ parseErrorAt off pleaseincludedecimalpoint- else return $ dbg2 "style from format subdirective" astyle+ else return $ dbg7 "style from format subdirective" astyle else customFailure $ parseErrorAt off $ printf "commodity directive symbol \"%s\" and format directive symbol \"%s\" should be the same" expectedsym acommodity
Hledger/Reports/AccountTransactionsReport.hs view
@@ -102,7 +102,7 @@ ts3 = filter (matchesTransaction thisacctq . filterTransactionPostings (And [realq, statusq])) ts2 -- maybe convert these transactions to cost or value- prices = journalPriceOracle j+ prices = journalPriceOracle (infer_value_ ropts) j styles = journalCommodityStyles j periodlast = fromMaybe (error' "journalApplyValuation: expected a non-empty journal") $ -- XXX shouldn't happen
Hledger/Reports/BalanceReport.hs view
@@ -70,8 +70,9 @@ (if invert_ then brNegate else id) $ (mappedsorteditems, mappedtotal) where- -- dbg1 = const id -- exclude from debug output- dbg1 s = let p = "balanceReport" in Hledger.Utils.dbg1 (p++" "++s) -- add prefix in debug output+ -- dbg = const id -- exclude from debug output+ dbg s = let p = "balanceReport" in Hledger.Utils.dbg4 (p++" "++s) -- add prefix in debug output+ dbg' s = let p = "balanceReport" in Hledger.Utils.dbg5 (p++" "++s) -- add prefix in debug output -- Get all the summed accounts & balances, according to the query, as an account tree. -- If doing cost valuation, amounts will be converted to cost first.@@ -81,27 +82,31 @@ -- per hledger_options.m4.md "Effect of --value on reports". valuedaccttree = mapAccounts avalue accttree where- avalue a@Account{..} = a{aebalance=bvalue aebalance, aibalance=bvalue aibalance}+ avalue a@Account{..} = a{aebalance=maybevalue aebalance, aibalance=maybevalue aibalance} where- bvalue = maybe id (mixedAmountApplyValuation (journalPriceOracle j) (journalCommodityStyles j) periodlast mreportlast today multiperiod) value_+ maybevalue = maybe id applyvaluation value_ where- periodlast =- fromMaybe (error' "balanceReport: expected a non-empty journal") $ -- XXX shouldn't happen- reportPeriodOrJournalLastDay ropts j- mreportlast = reportPeriodLastDay ropts- today = fromMaybe (error' "balanceReport: could not pick a valuation date, ReportOpts today_ is unset") today_- multiperiod = interval_ /= NoInterval+ applyvaluation = mixedAmountApplyValuation priceoracle styles periodlast mreportlast today multiperiod+ where+ priceoracle = journalPriceOracle infer_value_ j+ styles = journalCommodityStyles j+ periodlast = fromMaybe+ (error' "balanceReport: expected a non-empty journal") $ -- XXX shouldn't happen+ reportPeriodOrJournalLastDay ropts j+ mreportlast = reportPeriodLastDay ropts+ today = fromMaybe (error' "balanceReport: could not pick a valuation date, ReportOpts today_ is unset") today_+ multiperiod = interval_ /= NoInterval -- Modify this tree for display - depth limit, boring parents, zeroes - and convert to a list. displayaccts :: [Account] | queryDepth q == 0 =- dbg1 "displayaccts" $+ dbg' "displayaccts" $ take 1 $ clipAccountsAndAggregate (queryDepth q) $ flattenAccounts valuedaccttree- | flat_ ropts = dbg1 "displayaccts" $+ | flat_ ropts = dbg' "displayaccts" $ filterzeros $ filterempty $ drop 1 $ clipAccountsAndAggregate (queryDepth q) $ flattenAccounts valuedaccttree- | otherwise = dbg1 "displayaccts" $+ | otherwise = dbg' "displayaccts" $ filter (not.aboring) $ drop 1 $ flattenAccounts $ markboring $@@ -116,7 +121,7 @@ markboring = if no_elide_ then id else markBoringParentAccounts -- Make a report row for each account.- items = dbg1 "items" $ map (balanceReportItem ropts q) displayaccts+ items = dbg "items" $ map (balanceReportItem ropts q) displayaccts -- Sort report rows (except sorting by amount in tree mode, which was done above). sorteditems@@ -139,17 +144,17 @@ sortedrows = sortAccountItemsLike sortedanames anamesandrows -- Calculate the grand total.- total | not (flat_ ropts) = dbg1 "total" $ sum [amt | (_,_,indent,amt) <- items, indent == 0]- | otherwise = dbg1 "total" $+ total | not (flat_ ropts) = dbg "total" $ sum [amt | (_,_,indent,amt) <- items, indent == 0]+ | otherwise = dbg "total" $ if flatShowsExclusiveBalance then sum $ map fourth4 items else sum $ map aebalance $ clipAccountsAndAggregate 1 displayaccts -- Calculate percentages if needed.- mappedtotal | percent_ = dbg1 "mappedtotal" $ total `perdivide` total+ mappedtotal | percent_ = dbg "mappedtotal" $ total `perdivide` total | otherwise = total mappedsorteditems | percent_ =- dbg1 "mappedsorteditems" $+ dbg "mappedsorteditems" $ map (\(fname, sname, indent, amount) -> (fname, sname, indent, amount `perdivide` total)) sorteditems | otherwise = sorteditems
Hledger/Reports/EntriesReport.hs view
@@ -40,7 +40,7 @@ tvalue t@Transaction{..} = t{tpostings=map pvalue tpostings} where pvalue p = maybe p- (postingApplyValuation (journalPriceOracle j) (journalCommodityStyles j) periodlast mreportlast today False p)+ (postingApplyValuation (journalPriceOracle infer_value_ j) (journalCommodityStyles j) periodlast mreportlast today False p) value_ where periodlast = fromMaybe today $ reportPeriodOrJournalLastDay ropts j
Hledger/Reports/MultiBalanceReport.hs view
@@ -72,7 +72,11 @@ -- hledger's most powerful and useful report, used by the balance -- command (in multiperiod mode) and (via multiBalanceReport') by the bs/cf/is commands. multiBalanceReport :: Day -> ReportOpts -> Journal -> MultiBalanceReport-multiBalanceReport today ropts j = multiBalanceReportWith ropts (queryFromOpts today ropts) j (journalPriceOracle j)+multiBalanceReport today ropts j =+ multiBalanceReportWith ropts q j (journalPriceOracle infer j)+ where+ q = queryFromOpts today ropts+ infer = infer_value_ ropts -- | A helper for multiBalanceReport. This one takes an explicit Query -- instead of deriving one from ReportOpts, and an extra argument, a@@ -85,49 +89,52 @@ (if invert_ then prNegate else id) $ PeriodicReport colspans mappedsortedrows mappedtotalsrow where- dbg1 s = let p = "multiBalanceReport" in Hledger.Utils.dbg1 (p++" "++s) -- add prefix in this function's debug output- -- dbg1 = const id -- exclude this function from debug output+ -- add a prefix to this function's debug output+ dbg s = let p = "multiBalanceReport" in Hledger.Utils.dbg3 (p++" "++s)+ dbg' s = let p = "multiBalanceReport" in Hledger.Utils.dbg4 (p++" "++s)+ dbg'' s = let p = "multiBalanceReport" in Hledger.Utils.dbg5 (p++" "++s)+ -- dbg = const id -- exclude this function from debug output ---------------------------------------------------------------------- -- 1. Queries, report/column dates. - symq = dbg1 "symq" $ filterQuery queryIsSym $ dbg1 "requested q" q- depthq = dbg1 "depthq" $ filterQuery queryIsDepth q+ symq = dbg "symq" $ filterQuery queryIsSym $ dbg "requested q" q+ depthq = dbg "depthq" $ filterQuery queryIsDepth q depth = queryDepth depthq- depthless = dbg1 "depthless" . filterQuery (not . queryIsDepth)- datelessq = dbg1 "datelessq" $ filterQuery (not . queryIsDateOrDate2) q+ depthless = dbg "depthless" . filterQuery (not . queryIsDepth)+ datelessq = dbg "datelessq" $ filterQuery (not . queryIsDateOrDate2) q dateqcons = if date2_ then Date2 else Date -- The date span specified by -b/-e/-p options and query args if any.- requestedspan = dbg1 "requestedspan" $ queryDateSpan date2_ q+ requestedspan = dbg "requestedspan" $ queryDateSpan date2_ q -- If the requested span is open-ended, close it using the journal's end dates. -- This can still be the null (open) span if the journal is empty.- requestedspan' = dbg1 "requestedspan'" $ requestedspan `spanDefaultsFrom` journalDateSpan date2_ j+ requestedspan' = dbg "requestedspan'" $ requestedspan `spanDefaultsFrom` journalDateSpan date2_ j -- The list of interval spans enclosing the requested span. -- This list can be empty if the journal was empty, -- or if hledger-ui has added its special date:-tomorrow to the query -- and all txns are in the future.- intervalspans = dbg1 "intervalspans" $ splitSpan interval_ requestedspan'+ intervalspans = dbg "intervalspans" $ splitSpan interval_ requestedspan' -- The requested span enlarged to enclose a whole number of intervals. -- This can be the null span if there were no intervals.- reportspan = dbg1 "reportspan" $ DateSpan (maybe Nothing spanStart $ headMay intervalspans)+ reportspan = dbg "reportspan" $ DateSpan (maybe Nothing spanStart $ headMay intervalspans) (maybe Nothing spanEnd $ lastMay intervalspans) mreportstart = spanStart reportspan -- The user's query with no depth limit, and expanded to the report span -- if there is one (otherwise any date queries are left as-is, which -- handles the hledger-ui+future txns case above).- reportq = dbg1 "reportq" $ depthless $+ reportq = dbg "reportq" $ depthless $ if reportspan == nulldatespan then q else And [datelessq, reportspandatesq] where- reportspandatesq = dbg1 "reportspandatesq" $ dateqcons reportspan+ reportspandatesq = dbg "reportspandatesq" $ dateqcons reportspan -- The date spans to be included as report columns.- colspans :: [DateSpan] = dbg1 "colspans" $ splitSpan interval_ displayspan+ colspans :: [DateSpan] = dbg "colspans" $ splitSpan interval_ displayspan where displayspan- | empty_ = dbg1 "displayspan (-E)" reportspan -- all the requested intervals- | otherwise = dbg1 "displayspan" $ requestedspan `spanIntersect` matchedspan -- exclude leading/trailing empty intervals- matchedspan = dbg1 "matchedspan" . daysSpan $ map snd ps+ | empty_ = dbg "displayspan (-E)" reportspan -- all the requested intervals+ | otherwise = dbg "displayspan" $ requestedspan `spanIntersect` matchedspan -- exclude leading/trailing empty intervals+ matchedspan = dbg "matchedspan" . daysSpan $ map snd ps -- If doing cost valuation, convert amounts to cost. j' = journalSelectingAmountFromOpts ropts j@@ -137,9 +144,9 @@ -- Balances at report start date, from all earlier postings which otherwise match the query. -- These balances are unvalued except maybe converted to cost.- startbals :: [(AccountName, MixedAmount)] = dbg1 "startbals" $ map (\(a,_,_,b) -> (a,b)) startbalanceitems+ startbals :: [(AccountName, MixedAmount)] = dbg' "startbals" $ map (\(a,_,_,b) -> (a,b)) startbalanceitems where- (startbalanceitems,_) = dbg1 "starting balance report" $ balanceReport ropts''{value_=Nothing, percent_=False} startbalq j'+ (startbalanceitems,_) = dbg'' "starting balance report" $ balanceReport ropts''{value_=Nothing, percent_=False} startbalq j' where ropts' | tree_ ropts = ropts{no_elide_=True} | otherwise = ropts{accountlistmode_=ALFlat}@@ -149,14 +156,14 @@ -- q projected back before the report start date. -- When there's no report start date, in case there are future txns (the hledger-ui case above), -- we use emptydatespan to make sure they aren't counted as starting balance.- startbalq = dbg1 "startbalq" $ And [datelessq, dateqcons precedingspan]+ startbalq = dbg'' "startbalq" $ And [datelessq, dateqcons precedingspan] where precedingspan = case mreportstart of Just d -> DateSpan Nothing (Just d) Nothing -> emptydatespan -- The matched accounts with a starting balance. All of these should appear -- in the report even if they have no postings during the report period.- startaccts = dbg1 "startaccts" $ map fst startbals+ startaccts = dbg'' "startaccts" $ map fst startbals -- Helpers to look up an account's starting balance. startingBalanceFor a = fromMaybe nullmixedamt $ lookup a startbals @@ -165,7 +172,7 @@ -- Postings matching the query within the report period. ps :: [(Posting, Day)] =- dbg1 "ps" $+ dbg'' "ps" $ map postingWithDate $ journalPostings $ filterJournalAmounts symq $ -- remove amount parts excluded by cur:@@ -178,7 +185,7 @@ -- Group postings into their columns, with the column end dates. colps :: [([Posting], Maybe Day)] =- dbg1 "colps"+ dbg'' "colps" [ (posts, end) | (DateSpan _ end, posts) <- M.toList colMap ] where colMap = foldr addPosting emptyMap ps@@ -199,7 +206,7 @@ | tree_ ropts = filter ((depthq `matchesAccount`).aname) -- exclude deeper balances | otherwise = clipAccountsAndAggregate depth -- aggregate deeper balances at the depth limit colacctchanges :: [[(ClippedAccountName, MixedAmount)]] =- dbg1 "colacctchanges" $ map (acctChangesFromPostings . fst) colps+ dbg'' "colacctchanges" $ map (acctChangesFromPostings . fst) colps ---------------------------------------------------------------------- -- 5. Gather the account balance changes into a regular matrix including the accounts@@ -207,7 +214,7 @@ -- All account names that will be displayed, possibly depth-clipped. displayaccts :: [ClippedAccountName] =- dbg1 "displayaccts" $+ dbg'' "displayaccts" $ (if tree_ ropts then expandAccountNames else id) $ nub $ map (clipOrEllipsifyAccountName depth) $ if empty_ || balancetype_ == HistoricalBalance@@ -215,16 +222,16 @@ else allpostedaccts where allpostedaccts :: [AccountName] =- dbg1 "allpostedaccts" . sort . accountNamesFromPostings $ map fst ps+ dbg'' "allpostedaccts" . sort . accountNamesFromPostings $ map fst ps -- Each column's balance changes for each account, adding zeroes where needed. colallacctchanges :: [[(ClippedAccountName, MixedAmount)]] =- dbg1 "colallacctchanges"+ dbg'' "colallacctchanges" [ sortOn fst $ unionBy (\(a,_) (a',_) -> a == a') postedacctchanges zeroes | postedacctchanges <- colacctchanges ] where zeroes = [(a, nullmixedamt) | a <- displayaccts] -- Transpose to get each account's balance changes across all columns. acctchanges :: [(ClippedAccountName, [MixedAmount])] =- dbg1 "acctchanges"+ dbg'' "acctchanges" [(a, map snd abs) | abs@((a,_):_) <- transpose colallacctchanges] -- never null, or used when null... ----------------------------------------------------------------------@@ -232,18 +239,18 @@ -- One row per account, with account name info, row amounts, row total and row average. rows :: [MultiBalanceReportRow] =- dbg1 "rows" $+ dbg'' "rows" $ [ PeriodicReportRow a (accountNameLevel a) valuedrowbals rowtot rowavg- | (a,changes) <- dbg1 "acctchanges" acctchanges+ | (a,changes) <- dbg'' "acctchanges" acctchanges -- The row amounts to be displayed: per-period changes, -- zero-based cumulative totals, or -- starting-balance-based historical balances.- , let rowbals = dbg1 "rowbals" $ case balancetype_ of+ , let rowbals = dbg'' "rowbals" $ case balancetype_ of PeriodChange -> changes CumulativeChange -> drop 1 $ scanl (+) 0 changes HistoricalBalance -> drop 1 $ scanl (+) (startingBalanceFor a) changes -- We may be converting amounts to value, per hledger_options.m4.md "Effect of --value on reports".- , let valuedrowbals = dbg1 "valuedrowbals" $ [avalue periodlastday amt | (amt,periodlastday) <- zip rowbals lastdays]+ , let valuedrowbals = dbg'' "valuedrowbals" $ [avalue periodlastday amt | (amt,periodlastday) <- zip rowbals lastdays] -- The total and average for the row. -- These are always simply the sum/average of the displayed row amounts. -- Total for a cumulative/historical report is always zero.@@ -273,7 +280,7 @@ -- Sort the rows by amount or by account declaration order. This is a bit tricky. -- TODO: is it always ok to sort report rows after report has been generated, as a separate step ? sortedrows :: [MultiBalanceReportRow] =- dbg1 "sortedrows" $+ dbg' "sortedrows" $ sortrows rows where sortrows@@ -319,7 +326,7 @@ colamts = transpose . map prrAmounts $ filter isHighest rows where isHighest row = not (tree_ ropts) || prrName row `elem` highestlevelaccts coltotals :: [MixedAmount] =- dbg1 "coltotals" $ map sum colamts+ dbg'' "coltotals" $ map sum colamts -- Calculate the grand total and average. These are always the sum/average -- of the column totals. [grandtotal,grandaverage] =@@ -330,7 +337,7 @@ in amts -- Totals row. totalsrow :: PeriodicReportRow () MixedAmount =- dbg1 "totalsrow" $ PeriodicReportRow () 0 coltotals grandtotal grandaverage+ dbg' "totalsrow" $ PeriodicReportRow () 0 coltotals grandtotal grandaverage ---------------------------------------------------------------------- -- 9. Map the report rows to percentages if needed@@ -339,7 +346,7 @@ -- Perform the divisions to obtain percentages mappedsortedrows :: [MultiBalanceReportRow] = if not percent_ then sortedrows- else dbg1 "mappedsortedrows"+ else dbg'' "mappedsortedrows" [ PeriodicReportRow aname alevel (zipWith perdivide rowvals coltotals) (rowtotal `perdivide` grandtotal)@@ -347,7 +354,7 @@ | PeriodicReportRow aname alevel rowvals rowtotal rowavg <- sortedrows ] mappedtotalsrow :: PeriodicReportRow () MixedAmount- | percent_ = dbg1 "mappedtotalsrow" $ PeriodicReportRow () 0+ | percent_ = dbg'' "mappedtotalsrow" $ PeriodicReportRow () 0 (map (\t -> perdivide t t) coltotals) (perdivide grandtotal grandtotal) (perdivide grandaverage grandaverage)@@ -360,7 +367,8 @@ balanceReportFromMultiBalanceReport :: ReportOpts -> Query -> Journal -> BalanceReport balanceReportFromMultiBalanceReport opts q j = (rows', total) where- PeriodicReport _ rows (PeriodicReportRow _ _ totals _ _) = multiBalanceReportWith opts q j (journalPriceOracle j)+ PeriodicReport _ rows (PeriodicReportRow _ _ totals _ _) =+ multiBalanceReportWith opts q j (journalPriceOracle (infer_value_ opts) j) rows' = [( a , if flat_ opts then a else accountLeafName a -- BalanceReport expects full account name here with --flat , if tree_ opts then d-1 else 0 -- BalanceReport uses 0-based account depths
Hledger/Reports/PostingsReport.hs view
@@ -74,7 +74,7 @@ whichdate = whichDateFromOpts ropts depth = queryDepth q styles = journalCommodityStyles j- priceoracle = journalPriceOracle j+ priceoracle = journalPriceOracle infer_value_ j multiperiod = interval_ /= NoInterval today = fromMaybe (error' "postingsReport: could not pick a valuation date, ReportOpts today_ is unset") today_
Hledger/Reports/ReportOptions.hs view
@@ -93,6 +93,7 @@ ,interval_ :: Interval ,statuses_ :: [Status] -- ^ Zero, one, or two statuses to be matched ,value_ :: Maybe ValuationType -- ^ What value should amounts be converted to ?+ ,infer_value_ :: Bool -- ^ Infer market prices from transactions ? ,depth_ :: Maybe Int ,display_ :: Maybe DisplayExp -- XXX unused ? ,date2_ :: Bool@@ -161,6 +162,7 @@ def def def+ def rawOptsToReportOpts :: RawOpts -> IO ReportOpts rawOptsToReportOpts rawopts = checkReportOpts <$> do@@ -173,6 +175,7 @@ ,interval_ = intervalFromRawOpts rawopts' ,statuses_ = statusesFromRawOpts rawopts' ,value_ = valuationTypeFromRawOpts rawopts'+ ,infer_value_ = boolopt "infer-value" rawopts' ,depth_ = maybeintopt "depth" rawopts' ,display_ = maybedisplayopt d rawopts' ,date2_ = boolopt "date2" rawopts'@@ -317,8 +320,7 @@ -- | get period expression from --forecast option forecastPeriodFromRawOpts :: Day -> RawOpts -> Maybe DateSpan forecastPeriodFromRawOpts d opts =- case - dbg2 "forecastopt" $ maybestringopt "forecast" opts+ case maybestringopt "forecast" opts of Nothing -> Nothing Just "" -> Just nulldatespan@@ -478,13 +480,13 @@ reportSpan :: Journal -> ReportOpts -> IO DateSpan reportSpan j ropts = do (mspecifiedstartdate, mspecifiedenddate) <-- dbg2 "specifieddates" <$> specifiedStartEndDates ropts+ dbg3 "specifieddates" <$> specifiedStartEndDates ropts let DateSpan mjournalstartdate mjournalenddate =- dbg2 "journalspan" $ journalDateSpan False j -- ignore secondary dates+ dbg3 "journalspan" $ journalDateSpan False j -- ignore secondary dates mstartdate = mspecifiedstartdate <|> mjournalstartdate menddate = mspecifiedenddate <|> mjournalenddate- return $ dbg1 "reportspan" $ DateSpan mstartdate menddate+ return $ dbg3 "reportspan" $ DateSpan mstartdate menddate reportStartDate :: Journal -> ReportOpts -> IO (Maybe Day) reportStartDate j ropts = spanStart <$> reportSpan j ropts
Hledger/Utils/Debug.hs view
@@ -1,5 +1,33 @@ {-# LANGUAGE FlexibleContexts, TypeFamilies #-}--- | Debugging helpers+{- | Debugging helpers.++You can enable increasingly verbose debug output by adding --debug [1-9]+to a hledger command line. --debug with no argument means --debug 1.+This is implemented by calling dbgN or similar helpers, defined below.+These calls can be found throughout hledger code; they have been added+organically where it seemed likely they would be needed again.+The choice of debug level has not been very systematic.+202006 Here's a start at some guidelines, not yet applied project-wide:++Debug level: What to show:+------------ ---------------------------------------------------------+0 normal command output only (no warnings, eg)+1 (--debug) useful warnings, most common troubleshooting info, eg valuation+2 common troubleshooting info, more detail+3 report options selection+4 report generation+5 report generation, more detail+6 command line parsing+7 input file reading+8 input file reading, more detail+9 any other rarely needed / more in-depth info++Tip: when debugging with GHCI, the first run after loading Debug.hs sets the+debug level. If you need to change it, you must touch Debug.hs, :reload in GHCI,+then run the command with a new --debug value. Or, often it's more convenient+to add a temporary dbg0 and :reload (dbg0 always prints).++-} -- more: -- http://hackage.haskell.org/packages/archive/TraceUtils/0.1.0.2/doc/html/Debug-TraceUtils.html
hledger-lib.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 20f17b4cb289218f7b75159b42ad69840906c54c555a2191679edd3842b72e7b+-- hash: 22c04257dd0778ffcde96603d006e72ff6bf1b3da2ac7c3c12bc4e9df2064863 name: hledger-lib-version: 1.18+version: 1.18.1 synopsis: A reusable library providing the core functionality of hledger description: A reusable library containing hledger's core functionality. This is used by most hledger* packages so that they support the same
hledger_csv.5 view
@@ -1,6 +1,6 @@ .\"t -.TH "hledger_csv" "5" "June 2020" "hledger 1.18" "hledger User Manuals"+.TH "hledger_csv" "5" "June 2020" "hledger 1.18.1" "hledger User Manuals" @@ -961,7 +961,7 @@ .PP A posting amount can be set in one of these ways: .IP \[bu] 2-by assigning (with a fields list or field assigment) to+by assigning (with a fields list or field assignment) to \f[C]amountN\f[R] (posting N\[aq]s amount) or \f[C]amount\f[R] (posting 1\[aq]s amount) .IP \[bu] 2
hledger_csv.info view
@@ -3,8 +3,8 @@ File: hledger_csv.info, Node: Top, Next: EXAMPLES, Up: (dir) -hledger_csv(5) hledger 1.18-***************************+hledger_csv(5) hledger 1.18.1+***************************** CSV - how hledger reads CSV data, and the CSV rules file format @@ -907,7 +907,7 @@ A posting amount can be set in one of these ways: - * by assigning (with a fields list or field assigment) to 'amountN'+ * by assigning (with a fields list or field assignment) to 'amountN' (posting N's amount) or 'amount' (posting 1's amount) * by assigning to 'amountN-in' and 'amountN-out' (or 'amount-in' and@@ -1036,74 +1036,74 @@ Tag Table: Node: Top72-Node: EXAMPLES2174-Ref: #examples2280-Node: Basic2488-Ref: #basic2588-Node: Bank of Ireland3130-Ref: #bank-of-ireland3265-Node: Amazon4727-Ref: #amazon4845-Node: Paypal6564-Ref: #paypal6658-Node: CSV RULES14302-Ref: #csv-rules14411-Node: skip14687-Ref: #skip14780-Node: fields15155-Ref: #fields15277-Node: Transaction field names16442-Ref: #transaction-field-names16602-Node: Posting field names16713-Ref: #posting-field-names16865-Node: account16935-Ref: #account17051-Node: amount17588-Ref: #amount17719-Node: currency18826-Ref: #currency18961-Node: balance19167-Ref: #balance19301-Node: comment19618-Ref: #comment19735-Node: field assignment19898-Ref: #field-assignment20041-Node: separator20859-Ref: #separator20988-Node: if21399-Ref: #if21501-Node: end23657-Ref: #end23763-Node: date-format23987-Ref: #date-format24119-Node: newest-first24868-Ref: #newest-first25006-Node: include25689-Ref: #include25818-Node: balance-type26262-Ref: #balance-type26382-Node: TIPS27082-Ref: #tips27164-Node: Rapid feedback27420-Ref: #rapid-feedback27537-Node: Valid CSV27997-Ref: #valid-csv28127-Node: File Extension28319-Ref: #file-extension28471-Node: Reading multiple CSV files28881-Ref: #reading-multiple-csv-files29066-Node: Valid transactions29307-Ref: #valid-transactions29485-Node: Deduplicating importing30113-Ref: #deduplicating-importing30292-Node: Setting amounts31325-Ref: #setting-amounts31494-Node: Setting currency/commodity32480-Ref: #setting-currencycommodity32672-Node: Referencing other fields33475-Ref: #referencing-other-fields33675-Node: How CSV rules are evaluated34572-Ref: #how-csv-rules-are-evaluated34745+Node: EXAMPLES2178+Ref: #examples2284+Node: Basic2492+Ref: #basic2592+Node: Bank of Ireland3134+Ref: #bank-of-ireland3269+Node: Amazon4731+Ref: #amazon4849+Node: Paypal6568+Ref: #paypal6662+Node: CSV RULES14306+Ref: #csv-rules14415+Node: skip14691+Ref: #skip14784+Node: fields15159+Ref: #fields15281+Node: Transaction field names16446+Ref: #transaction-field-names16606+Node: Posting field names16717+Ref: #posting-field-names16869+Node: account16939+Ref: #account17055+Node: amount17592+Ref: #amount17723+Node: currency18830+Ref: #currency18965+Node: balance19171+Ref: #balance19305+Node: comment19622+Ref: #comment19739+Node: field assignment19902+Ref: #field-assignment20045+Node: separator20863+Ref: #separator20992+Node: if21403+Ref: #if21505+Node: end23661+Ref: #end23767+Node: date-format23991+Ref: #date-format24123+Node: newest-first24872+Ref: #newest-first25010+Node: include25693+Ref: #include25822+Node: balance-type26266+Ref: #balance-type26386+Node: TIPS27086+Ref: #tips27168+Node: Rapid feedback27424+Ref: #rapid-feedback27541+Node: Valid CSV28001+Ref: #valid-csv28131+Node: File Extension28323+Ref: #file-extension28475+Node: Reading multiple CSV files28885+Ref: #reading-multiple-csv-files29070+Node: Valid transactions29311+Ref: #valid-transactions29489+Node: Deduplicating importing30117+Ref: #deduplicating-importing30296+Node: Setting amounts31329+Ref: #setting-amounts31498+Node: Setting currency/commodity32485+Ref: #setting-currencycommodity32677+Node: Referencing other fields33480+Ref: #referencing-other-fields33680+Node: How CSV rules are evaluated34577+Ref: #how-csv-rules-are-evaluated34750 End Tag Table
hledger_csv.txt view
@@ -710,7 +710,7 @@ Setting amounts A posting amount can be set in one of these ways: - o by assigning (with a fields list or field assigment) to amountN+ o by assigning (with a fields list or field assignment) to amountN (posting N's amount) or amount (posting 1's amount) o by assigning to amountN-in and amountN-out (or amount-in and amount-@@ -852,4 +852,4 @@ -hledger 1.18 June 2020 hledger_csv(5)+hledger 1.18.1 June 2020 hledger_csv(5)
hledger_journal.5 view
@@ -1,6 +1,6 @@ .\"t -.TH "hledger_journal" "5" "June 2020" "hledger 1.18" "hledger User Manuals"+.TH "hledger_journal" "5" "June 2020" "hledger 1.18.1" "hledger User Manuals" @@ -1143,15 +1143,20 @@ If the file path does not begin with a slash, it is relative to the current file\[aq]s folder. .PP-It may contain glob patterns to match multiple files, eg:+A tilde means home directory, eg: \f[C]include \[ti]/main.journal\f[R].+.PP+The path may contain glob patterns to match multiple files, eg: \f[C]include *.journal\f[R]. .PP-Or a tilde, meaning home directory:-\f[C]include \[ti]/main.journal\f[R].+There is limited support for recursive wildcards: \f[C]**/\f[R] (the+slash is required) matches 0 or more subdirectories.+It\[aq]s not super convenient since you have to avoid include cycles and+including directories, but this can be done, eg:+\f[C]include */**/*.journal\f[R]. .PP-It may also be prefixed to force a specific file format, overriding the-file extension (as described in hledger.1 -> Input files):-\f[C]include timedot:\[ti]/notes/2020*.md\f[R].+The path may also be prefixed to force a specific file format,+overriding the file extension (as described in hledger.1 -> Input+files): \f[C]include timedot:\[ti]/notes/2020*.md\f[R]. .SS Default year .PP You can set a default year to be used for subsequent dates which
hledger_journal.info view
@@ -4,8 +4,8 @@ File: hledger_journal.info, Node: Top, Up: (dir) -hledger_journal(5) hledger 1.18-*******************************+hledger_journal(5) hledger 1.18.1+********************************* Journal - hledger's default file format, representing a General Journal @@ -1023,15 +1023,20 @@ If the file path does not begin with a slash, it is relative to the current file's folder. - It may contain glob patterns to match multiple files, eg: 'include-*.journal'.+ A tilde means home directory, eg: 'include ~/main.journal'. - Or a tilde, meaning home directory: 'include ~/main.journal'.+ The path may contain glob patterns to match multiple files, eg:+'include *.journal'. - It may also be prefixed to force a specific file format, overriding-the file extension (as described in hledger.1 -> Input files): 'include-timedot:~/notes/2020*.md'.+ There is limited support for recursive wildcards: '**/' (the slash is+required) matches 0 or more subdirectories. It's not super convenient+since you have to avoid include cycles and including directories, but+this can be done, eg: 'include */**/*.journal'. + The path may also be prefixed to force a specific file format,+overriding the file extension (as described in hledger.1 -> Input+files): 'include timedot:~/notes/2020*.md'.+ File: hledger_journal.info, Node: Default year, Next: Declaring commodities, Prev: Including other files, Up: Directives @@ -1823,124 +1828,124 @@ Tag Table: Node: Top76-Node: Transactions1869-Ref: #transactions1961-Node: Dates3245-Ref: #dates3344-Node: Simple dates3409-Ref: #simple-dates3535-Node: Secondary dates4044-Ref: #secondary-dates4198-Node: Posting dates5534-Ref: #posting-dates5663-Node: Status7035-Ref: #status7156-Node: Description8864-Ref: #description8998-Node: Payee and note9318-Ref: #payee-and-note9432-Node: Comments9767-Ref: #comments9893-Node: Tags11087-Ref: #tags11202-Node: Postings12595-Ref: #postings12723-Node: Virtual postings13749-Ref: #virtual-postings13866-Node: Account names15171-Ref: #account-names15312-Node: Amounts15799-Ref: #amounts15938-Node: Digit group marks17046-Ref: #digit-group-marks17194-Node: Amount display style18132-Ref: #amount-display-style18286-Node: Transaction prices19723-Ref: #transaction-prices19895-Node: Lot prices and lot dates22227-Ref: #lot-prices-and-lot-dates22424-Node: Balance assertions22912-Ref: #balance-assertions23098-Node: Assertions and ordering24131-Ref: #assertions-and-ordering24319-Node: Assertions and included files25019-Ref: #assertions-and-included-files25262-Node: Assertions and multiple -f options25595-Ref: #assertions-and-multiple--f-options25851-Node: Assertions and commodities25983-Ref: #assertions-and-commodities26215-Node: Assertions and prices27372-Ref: #assertions-and-prices27586-Node: Assertions and subaccounts28026-Ref: #assertions-and-subaccounts28255-Node: Assertions and virtual postings28579-Ref: #assertions-and-virtual-postings28821-Node: Assertions and precision28963-Ref: #assertions-and-precision29156-Node: Balance assignments29423-Ref: #balance-assignments29597-Node: Balance assignments and prices30761-Ref: #balance-assignments-and-prices30933-Node: Directives31157-Ref: #directives31316-Node: Directives and multiple files37007-Ref: #directives-and-multiple-files37190-Node: Comment blocks37854-Ref: #comment-blocks38037-Node: Including other files38213-Ref: #including-other-files38393-Node: Default year39044-Ref: #default-year39213-Node: Declaring commodities39620-Ref: #declaring-commodities39803-Node: Default commodity41609-Ref: #default-commodity41795-Node: Declaring market prices42684-Ref: #declaring-market-prices42879-Node: Declaring accounts43736-Ref: #declaring-accounts43922-Node: Account comments44847-Ref: #account-comments45010-Node: Account subdirectives45434-Ref: #account-subdirectives45629-Node: Account types45942-Ref: #account-types46126-Node: Account display order47765-Ref: #account-display-order47935-Node: Rewriting accounts49086-Ref: #rewriting-accounts49271-Node: Basic aliases50028-Ref: #basic-aliases50174-Node: Regex aliases50878-Ref: #regex-aliases51050-Node: Combining aliases51768-Ref: #combining-aliases51961-Node: Aliases and multiple files53237-Ref: #aliases-and-multiple-files53446-Node: end aliases54025-Ref: #end-aliases54182-Node: Default parent account54283-Ref: #default-parent-account54451-Node: Periodic transactions55335-Ref: #periodic-transactions55510-Node: Periodic rule syntax57382-Ref: #periodic-rule-syntax57588-Node: Two spaces between period expression and description!58292-Ref: #two-spaces-between-period-expression-and-description58611-Node: Forecasting with periodic transactions59295-Ref: #forecasting-with-periodic-transactions59600-Node: Budgeting with periodic transactions61655-Ref: #budgeting-with-periodic-transactions61894-Node: Auto postings62343-Ref: #auto-postings62483-Node: Auto postings and multiple files64662-Ref: #auto-postings-and-multiple-files64866-Node: Auto postings and dates65075-Ref: #auto-postings-and-dates65349-Node: Auto postings and transaction balancing / inferred amounts / balance assertions65524-Ref: #auto-postings-and-transaction-balancing-inferred-amounts-balance-assertions65875-Node: Auto posting tags66217-Ref: #auto-posting-tags66432+Node: Transactions1873+Ref: #transactions1965+Node: Dates3249+Ref: #dates3348+Node: Simple dates3413+Ref: #simple-dates3539+Node: Secondary dates4048+Ref: #secondary-dates4202+Node: Posting dates5538+Ref: #posting-dates5667+Node: Status7039+Ref: #status7160+Node: Description8868+Ref: #description9002+Node: Payee and note9322+Ref: #payee-and-note9436+Node: Comments9771+Ref: #comments9897+Node: Tags11091+Ref: #tags11206+Node: Postings12599+Ref: #postings12727+Node: Virtual postings13753+Ref: #virtual-postings13870+Node: Account names15175+Ref: #account-names15316+Node: Amounts15803+Ref: #amounts15942+Node: Digit group marks17050+Ref: #digit-group-marks17198+Node: Amount display style18136+Ref: #amount-display-style18290+Node: Transaction prices19727+Ref: #transaction-prices19899+Node: Lot prices and lot dates22231+Ref: #lot-prices-and-lot-dates22428+Node: Balance assertions22916+Ref: #balance-assertions23102+Node: Assertions and ordering24135+Ref: #assertions-and-ordering24323+Node: Assertions and included files25023+Ref: #assertions-and-included-files25266+Node: Assertions and multiple -f options25599+Ref: #assertions-and-multiple--f-options25855+Node: Assertions and commodities25987+Ref: #assertions-and-commodities26219+Node: Assertions and prices27376+Ref: #assertions-and-prices27590+Node: Assertions and subaccounts28030+Ref: #assertions-and-subaccounts28259+Node: Assertions and virtual postings28583+Ref: #assertions-and-virtual-postings28825+Node: Assertions and precision28967+Ref: #assertions-and-precision29160+Node: Balance assignments29427+Ref: #balance-assignments29601+Node: Balance assignments and prices30765+Ref: #balance-assignments-and-prices30937+Node: Directives31161+Ref: #directives31320+Node: Directives and multiple files37011+Ref: #directives-and-multiple-files37194+Node: Comment blocks37858+Ref: #comment-blocks38041+Node: Including other files38217+Ref: #including-other-files38397+Node: Default year39321+Ref: #default-year39490+Node: Declaring commodities39897+Ref: #declaring-commodities40080+Node: Default commodity41886+Ref: #default-commodity42072+Node: Declaring market prices42961+Ref: #declaring-market-prices43156+Node: Declaring accounts44013+Ref: #declaring-accounts44199+Node: Account comments45124+Ref: #account-comments45287+Node: Account subdirectives45711+Ref: #account-subdirectives45906+Node: Account types46219+Ref: #account-types46403+Node: Account display order48042+Ref: #account-display-order48212+Node: Rewriting accounts49363+Ref: #rewriting-accounts49548+Node: Basic aliases50305+Ref: #basic-aliases50451+Node: Regex aliases51155+Ref: #regex-aliases51327+Node: Combining aliases52045+Ref: #combining-aliases52238+Node: Aliases and multiple files53514+Ref: #aliases-and-multiple-files53723+Node: end aliases54302+Ref: #end-aliases54459+Node: Default parent account54560+Ref: #default-parent-account54728+Node: Periodic transactions55612+Ref: #periodic-transactions55787+Node: Periodic rule syntax57659+Ref: #periodic-rule-syntax57865+Node: Two spaces between period expression and description!58569+Ref: #two-spaces-between-period-expression-and-description58888+Node: Forecasting with periodic transactions59572+Ref: #forecasting-with-periodic-transactions59877+Node: Budgeting with periodic transactions61932+Ref: #budgeting-with-periodic-transactions62171+Node: Auto postings62620+Ref: #auto-postings62760+Node: Auto postings and multiple files64939+Ref: #auto-postings-and-multiple-files65143+Node: Auto postings and dates65352+Ref: #auto-postings-and-dates65626+Node: Auto postings and transaction balancing / inferred amounts / balance assertions65801+Ref: #auto-postings-and-transaction-balancing-inferred-amounts-balance-assertions66152+Node: Auto posting tags66494+Ref: #auto-posting-tags66709 End Tag Table
hledger_journal.txt view
@@ -792,18 +792,23 @@ If the file path does not begin with a slash, it is relative to the current file's folder. - It may contain glob patterns to match multiple files, eg: include+ A tilde means home directory, eg: include ~/main.journal.++ The path may contain glob patterns to match multiple files, eg: include *.journal. - Or a tilde, meaning home directory: include ~/main.journal.+ There is limited support for recursive wildcards: **/ (the slash is re-+ quired) matches 0 or more subdirectories. It's not super convenient+ since you have to avoid include cycles and including directories, but+ this can be done, eg: include */**/*.journal. - It may also be prefixed to force a specific file format, overriding the- file extension (as described in hledger.1 -> Input files): include- timedot:~/notes/2020*.md.+ The path may also be prefixed to force a specific file format, overrid-+ ing the file extension (as described in hledger.1 -> Input files): in-+ clude timedot:~/notes/2020*.md. Default year- You can set a default year to be used for subsequent dates which don't- specify a year. This is a line beginning with Y followed by the year.+ You can set a default year to be used for subsequent dates which don't+ specify a year. This is a line beginning with Y followed by the year. Eg: Y2009 ; set default year to 2009@@ -825,19 +830,19 @@ Declaring commodities The commodity directive has several functions: - 1. It declares commodities which may be used in the journal. This is+ 1. It declares commodities which may be used in the journal. This is currently not enforced, but can serve as documentation. - 2. It declares what decimal mark character (period or comma) to expect- when parsing input - useful to disambiguate international number- formats in your data. (Without this, hledger will parse both 1,000+ 2. It declares what decimal mark character (period or comma) to expect+ when parsing input - useful to disambiguate international number+ formats in your data. (Without this, hledger will parse both 1,000 and 1.000 as 1). - 3. It declares the amount display style to use in output - decimal and+ 3. It declares the amount display style to use in output - decimal and digit group marks, number of decimal places, symbol placement etc. - You are likely to run into one of the problems solved by commodity di-- rectives, sooner or later, so it's a good idea to just always use them+ You are likely to run into one of the problems solved by commodity di-+ rectives, sooner or later, so it's a good idea to just always use them to declare your commodities. A commodity directive is just the word commodity followed by an amount.@@ -850,8 +855,8 @@ ; separating thousands with comma. commodity 1,000.0000 AAAA - or on multiple lines, using the "format" subdirective. (In this case- the commodity symbol appears twice and should be the same in both+ or on multiple lines, using the "format" subdirective. (In this case+ the commodity symbol appears twice and should be the same in both places.): ; commodity SYMBOL@@ -864,22 +869,22 @@ format INR 1,00,00,000.00 The quantity of the amount does not matter; only the format is signifi-- cant. The number must include a decimal mark: either a period or a+ cant. The number must include a decimal mark: either a period or a comma, followed by 0 or more decimal digits. - Note hledger normally uses banker's rounding, so 0.5 displayed with+ Note hledger normally uses banker's rounding, so 0.5 displayed with zero decimal digits is "0". (More at Amount display style.) Default commodity- The D directive sets a default commodity, to be used for amounts with-+ The D directive sets a default commodity, to be used for amounts with- out a commodity symbol (ie, plain numbers). This commodity will be ap- plied to all subsequent commodity-less amounts, or until the next D di- rective. (Note, this is different from Ledger's D.) - For compatibility/historical reasons, D also acts like a commodity di-+ For compatibility/historical reasons, D also acts like a commodity di- rective, setting the commodity's display style (for output) and decimal mark (for parsing input). As with commodity, the amount must always be- written with a decimal mark (period or comma). If both directives are+ written with a decimal mark (period or comma). If both directives are used, commodity's style takes precedence. The syntax is D AMOUNT. Eg:@@ -893,9 +898,9 @@ b Declaring market prices- The P directive declares a market price, which is an exchange rate be-- tween two commodities on a certain date. (In Ledger, they are called- "historical prices".) These are often obtained from a stock exchange,+ The P directive declares a market price, which is an exchange rate be-+ tween two commodities on a certain date. (In Ledger, they are called+ "historical prices".) These are often obtained from a stock exchange, cryptocurrency exchange, or the foreign exchange market. Here is the format:@@ -906,16 +911,16 @@ o COMMODITYA is the symbol of the commodity being priced - o COMMODITYBAMOUNT is an amount (symbol and quantity) in a second com-+ o COMMODITYBAMOUNT is an amount (symbol and quantity) in a second com- modity, giving the price in commodity B of one unit of commodity A. - These two market price directives say that one euro was worth 1.35 US+ These two market price directives say that one euro was worth 1.35 US dollars during 2009, and $1.40 from 2010 onward: P 2009/1/1 EUR $1.35 P 2010/1/1 EUR $1.40 - The -V, -X and --value flags use these market prices to show amount+ The -V, -X and --value flags use these market prices to show amount values in another commodity. See Valuation. Declaring accounts@@ -925,20 +930,20 @@ o They can document your intended chart of accounts, providing a refer- ence. - o They can store extra information about accounts (account numbers,+ o They can store extra information about accounts (account numbers, notes, etc.) - o They can help hledger know your accounts' types (asset, liability,- equity, revenue, expense), useful for reports like balancesheet and+ o They can help hledger know your accounts' types (asset, liability,+ equity, revenue, expense), useful for reports like balancesheet and incomestatement. - o They control account display order in reports, allowing non-alpha-+ o They control account display order in reports, allowing non-alpha- betic sorting (eg Revenues to appear above Expenses). - o They help with account name completion in the add command, hledger-+ o They help with account name completion in the add command, hledger- iadd, hledger-web, ledger-mode etc. - The simplest form is just the word account followed by a hledger-style+ The simplest form is just the word account followed by a hledger-style account name, eg: account assets:bank:checking@@ -946,7 +951,7 @@ Account comments Comments, beginning with a semicolon, can be added: - o on the same line, after two or more spaces (because ; is allowed in+ o on the same line, after two or more spaces (because ; is allowed in account names) o on the next lines, indented@@ -960,7 +965,7 @@ Same-line comments are not supported by Ledger, or hledger <1.13. Account subdirectives- We also allow (and ignore) Ledger-style indented subdirectives, just+ We also allow (and ignore) Ledger-style indented subdirectives, just for compatibility.: account assets:bank:checking@@ -973,18 +978,18 @@ [LEDGER-STYLE SUBDIRECTIVES, IGNORED] Account types- hledger recognises five types (or classes) of account: Asset, Liabil-- ity, Equity, Revenue, Expense. This is used by a few accounting-aware+ hledger recognises five types (or classes) of account: Asset, Liabil-+ ity, Equity, Revenue, Expense. This is used by a few accounting-aware reports such as balancesheet, incomestatement and cashflow. Auto-detected account types If you name your top-level accounts with some variation of assets, lia-- bilities/debts, equity, revenues/income, or expenses, their types are+ bilities/debts, equity, revenues/income, or expenses, their types are detected automatically. Account types declared with tags- More generally, you can declare an account's type with an account di-- rective, by writing a type: tag in a comment, followed by one of the+ More generally, you can declare an account's type with an account di-+ rective, by writing a type: tag in a comment, followed by one of the words Asset, Liability, Equity, Revenue, Expense, or one of the letters ALERX (case insensitive): @@ -995,8 +1000,8 @@ account expenses ; type:Expense Account types declared with account type codes- Or, you can write one of those letters separated from the account name- by two or more spaces, but this should probably be considered depre-+ Or, you can write one of those letters separated from the account name+ by two or more spaces, but this should probably be considered depre- cated as of hledger 1.13: account assets A@@ -1006,7 +1011,7 @@ account expenses X Overriding auto-detected types- If you ever override the types of those auto-detected english account+ If you ever override the types of those auto-detected english account names mentioned above, you might need to help the reports a bit. Eg: ; make "liabilities" not have the liability type - who knows why@@ -1017,8 +1022,8 @@ account - ; type:L Account display order- Account directives also set the order in which accounts are displayed,- eg in reports, the hledger-ui accounts screen, and the hledger-web+ Account directives also set the order in which accounts are displayed,+ eg in reports, the hledger-ui accounts screen, and the hledger-web sidebar. By default accounts are listed in alphabetical order. But if you have these account directives in the journal: @@ -1040,20 +1045,20 @@ Undeclared accounts, if any, are displayed last, in alphabetical order. - Note that sorting is done at each level of the account tree (within- each group of sibling accounts under the same parent). And currently,+ Note that sorting is done at each level of the account tree (within+ each group of sibling accounts under the same parent). And currently, this directive: account other:zoo - would influence the position of zoo among other's subaccounts, but not+ would influence the position of zoo among other's subaccounts, but not the position of other among the top-level accounts. This means: - o you will sometimes declare parent accounts (eg account other above)+ o you will sometimes declare parent accounts (eg account other above) that you don't intend to post to, just to customize their display or- der - o sibling accounts stay together (you couldn't display x:y in between+ o sibling accounts stay together (you couldn't display x:y in between a:b and a:c). Rewriting accounts@@ -1071,14 +1076,14 @@ o customising reports Account aliases also rewrite account names in account directives. They- do not affect account names being entered via hledger add or hledger-+ do not affect account names being entered via hledger add or hledger- web. See also Rewrite account names. Basic aliases- To set an account alias, use the alias directive in your journal file.- This affects all subsequent journal entries in the current file or its+ To set an account alias, use the alias directive in your journal file.+ This affects all subsequent journal entries in the current file or its included files. The spaces around the = are optional: alias OLD = NEW@@ -1086,49 +1091,49 @@ Or, you can use the --alias 'OLD=NEW' option on the command line. This affects all entries. It's useful for trying out aliases interactively. - OLD and NEW are case sensitive full account names. hledger will re-- place any occurrence of the old account name with the new one. Subac-+ OLD and NEW are case sensitive full account names. hledger will re-+ place any occurrence of the old account name with the new one. Subac- counts are also affected. Eg: alias checking = assets:bank:wells fargo:checking ; rewrites "checking" to "assets:bank:wells fargo:checking", or "checking:a" to "assets:bank:wells fargo:checking:a" Regex aliases- There is also a more powerful variant that uses a regular expression,+ There is also a more powerful variant that uses a regular expression, indicated by the forward slashes: alias /REGEX/ = REPLACEMENT or --alias '/REGEX/=REPLACEMENT'. - REGEX is a case-insensitive regular expression. Anywhere it matches- inside an account name, the matched part will be replaced by REPLACE-- MENT. If REGEX contains parenthesised match groups, these can be ref-+ REGEX is a case-insensitive regular expression. Anywhere it matches+ inside an account name, the matched part will be replaced by REPLACE-+ MENT. If REGEX contains parenthesised match groups, these can be ref- erenced by the usual numeric backreferences in REPLACEMENT. Eg: alias /^(.+):bank:([^:]+)(.*)/ = \1:\2 \3 ; rewrites "assets:bank:wells fargo:checking" to "assets:wells fargo checking" - Also note that REPLACEMENT continues to the end of line (or on command- line, to end of option argument), so it can contain trailing white-+ Also note that REPLACEMENT continues to the end of line (or on command+ line, to end of option argument), so it can contain trailing white- space. Combining aliases- You can define as many aliases as you like, using journal directives+ You can define as many aliases as you like, using journal directives and/or command line options. - Recursive aliases - where an account name is rewritten by one alias,- then by another alias, and so on - are allowed. Each alias sees the+ Recursive aliases - where an account name is rewritten by one alias,+ then by another alias, and so on - are allowed. Each alias sees the effect of previously applied aliases. - In such cases it can be important to understand which aliases will be- applied and in which order. For (each account name in) each journal+ In such cases it can be important to understand which aliases will be+ applied and in which order. For (each account name in) each journal entry, we apply: - 1. alias directives preceding the journal entry, most recently parsed+ 1. alias directives preceding the journal entry, most recently parsed first (ie, reading upward from the journal entry, bottom to top) - 2. --alias options, in the order they appeared on the command line+ 2. --alias options, in the order they appeared on the command line (left to right). In other words, for (an account name in) a given journal entry:@@ -1139,20 +1144,20 @@ o aliases defined after/below the entry do not affect it. - This gives nearby aliases precedence over distant ones, and helps pro-- vide semantic stability - aliases will keep working the same way inde-+ This gives nearby aliases precedence over distant ones, and helps pro-+ vide semantic stability - aliases will keep working the same way inde- pendent of which files are being read and in which order. - In case of trouble, adding --debug=6 to the command line will show+ In case of trouble, adding --debug=6 to the command line will show which aliases are being applied when. Aliases and multiple files- As explained at Directives and multiple files, alias directives do not+ As explained at Directives and multiple files, alias directives do not affect parent or sibling files. Eg in this command, hledger -f a.aliases -f b.journal - account aliases defined in a.aliases will not affect b.journal. In-+ account aliases defined in a.aliases will not affect b.journal. In- cluding the aliases doesn't work either: include a.aliases@@ -1174,14 +1179,14 @@ include c.journal ; also affected end aliases- You can clear (forget) all currently defined aliases with the end+ You can clear (forget) all currently defined aliases with the end aliases directive: end aliases Default parent account- You can specify a parent account which will be prepended to all ac-- counts within a section of the journal. Use the apply account and end+ You can specify a parent account which will be prepended to all ac-+ counts within a section of the journal. Use the apply account and end apply account directives like so: apply account home@@ -1198,7 +1203,7 @@ home:food $10 home:cash $-10 - If end apply account is omitted, the effect lasts to the end of the+ If end apply account is omitted, the effect lasts to the end of the file. Included files are also affected, eg: apply account business@@ -1207,50 +1212,50 @@ apply account personal include personal.journal - Prior to hledger 1.0, legacy account and end spellings were also sup-+ Prior to hledger 1.0, legacy account and end spellings were also sup- ported. - A default parent account also affects account directives. It does not- affect account names being entered via hledger add or hledger-web. If- account aliases are present, they are applied after the default parent+ A default parent account also affects account directives. It does not+ affect account names being entered via hledger add or hledger-web. If+ account aliases are present, they are applied after the default parent account. Periodic transactions- Periodic transaction rules describe transactions that recur. They al-- low hledger to generate temporary future transactions to help with- forecasting, so you don't have to write out each one in the journal,- and it's easy to try out different forecasts. Secondly, they are also+ Periodic transaction rules describe transactions that recur. They al-+ low hledger to generate temporary future transactions to help with+ forecasting, so you don't have to write out each one in the journal,+ and it's easy to try out different forecasts. Secondly, they are also used to define the budgets shown in budget reports. - Periodic transactions can be a little tricky, so before you use them,+ Periodic transactions can be a little tricky, so before you use them, read this whole section - or at least these tips: - 1. Two spaces accidentally added or omitted will cause you trouble -+ 1. Two spaces accidentally added or omitted will cause you trouble - read about this below. - 2. For troubleshooting, show the generated transactions with hledger- print --forecast tag:generated or hledger register --forecast+ 2. For troubleshooting, show the generated transactions with hledger+ print --forecast tag:generated or hledger register --forecast tag:generated. - 3. Forecasted transactions will begin only after the last non-fore-+ 3. Forecasted transactions will begin only after the last non-fore- casted transaction's date. - 4. Forecasted transactions will end 6 months from today, by default.+ 4. Forecasted transactions will end 6 months from today, by default. See below for the exact start/end rules. - 5. period expressions can be tricky. Their documentation needs im-+ 5. period expressions can be tricky. Their documentation needs im- provement, but is worth studying. - 6. Some period expressions with a repeating interval must begin on a- natural boundary of that interval. Eg in weekly from DATE, DATE- must be a monday. ~ weekly from 2019/10/1 (a tuesday) will give an+ 6. Some period expressions with a repeating interval must begin on a+ natural boundary of that interval. Eg in weekly from DATE, DATE+ must be a monday. ~ weekly from 2019/10/1 (a tuesday) will give an error. 7. Other period expressions with an interval are automatically expanded- to cover a whole number of that interval. (This is done to improve+ to cover a whole number of that interval. (This is done to improve reports, but it also affects periodic transactions. Yes, it's a bit- inconsistent with the above.) Eg: ~ every 10th day of month from- 2020/01, which is equivalent to ~ every 10th day of month from+ inconsistent with the above.) Eg: ~ every 10th day of month from+ 2020/01, which is equivalent to ~ every 10th day of month from 2020/01/01, will be adjusted to start on 2019/12/10. Periodic rule syntax@@ -1262,17 +1267,17 @@ expenses:rent $2000 assets:bank:checking - There is an additional constraint on the period expression: the start- date must fall on a natural boundary of the interval. Eg monthly from+ There is an additional constraint on the period expression: the start+ date must fall on a natural boundary of the interval. Eg monthly from 2018/1/1 is valid, but monthly from 2018/1/15 is not. - Partial or relative dates (M/D, D, tomorrow, last week) in the period- expression can work (useful or not). They will be relative to today's- date, unless a Y default year directive is in effect, in which case+ Partial or relative dates (M/D, D, tomorrow, last week) in the period+ expression can work (useful or not). They will be relative to today's+ date, unless a Y default year directive is in effect, in which case they will be relative to Y/1/1. Two spaces between period expression and description!- If the period expression is followed by a transaction description,+ If the period expression is followed by a transaction description, these must be separated by two or more spaces. This helps hledger know where the period expression ends, so that descriptions can not acciden- tally alter their meaning, as in this example:@@ -1286,68 +1291,68 @@ So, - o Do write two spaces between your period expression and your transac-+ o Do write two spaces between your period expression and your transac- tion description, if any. - o Don't accidentally write two spaces in the middle of your period ex-+ o Don't accidentally write two spaces in the middle of your period ex- pression. Forecasting with periodic transactions- The --forecast flag activates any periodic transaction rules in the- journal. They will generate temporary recurring transactions, which- are not saved in the journal, but will appear in all reports (eg+ The --forecast flag activates any periodic transaction rules in the+ journal. They will generate temporary recurring transactions, which+ are not saved in the journal, but will appear in all reports (eg print). This can be useful for estimating balances into the future, or- experimenting with different scenarios. Or, it can be used as a data+ experimenting with different scenarios. Or, it can be used as a data entry aid: describe recurring transactions, and every so often copy the output of print --forecast into the journal. - These transactions will have an extra tag indicating which periodic+ These transactions will have an extra tag indicating which periodic rule generated them: generated-transaction:~ PERIODICEXPR. And a simi-- lar, hidden tag (beginning with an underscore) which, because it's- never displayed by print, can be used to match transactions generated+ lar, hidden tag (beginning with an underscore) which, because it's+ never displayed by print, can be used to match transactions generated "just now": _generated-transaction:~ PERIODICEXPR. - Periodic transactions are generated within some forecast period. By+ Periodic transactions are generated within some forecast period. By default, this o begins on the later of o the report start date if specified with -b/-p/date: - o the day after the latest normal (non-periodic) transaction in the+ o the day after the latest normal (non-periodic) transaction in the journal, or today if there are no normal transactions. - o ends on the report end date if specified with -e/-p/date:, or 6+ o ends on the report end date if specified with -e/-p/date:, or 6 months (180 days) from today. - This means that periodic transactions will begin only after the latest- recorded transaction. And a recorded transaction dated in the future- can prevent generation of periodic transactions. (You can avoid that+ This means that periodic transactions will begin only after the latest+ recorded transaction. And a recorded transaction dated in the future+ can prevent generation of periodic transactions. (You can avoid that by writing the future transaction as a one-time periodic rule instead - put tilde before the date, eg ~ YYYY-MM-DD ...). Or, you can set your own arbitrary "forecast period", which can overlap- recorded transactions, and need not be in the future, by providing an- option argument, like --forecast=PERIODEXPR. Note the equals sign is+ recorded transactions, and need not be in the future, by providing an+ option argument, like --forecast=PERIODEXPR. Note the equals sign is required, a space won't work. PERIODEXPR is a period expression, which- can specify the start date, end date, or both, like in a date: query.- (See also hledger.1 -> Report start & end date). Some examples:+ can specify the start date, end date, or both, like in a date: query.+ (See also hledger.1 -> Report start & end date). Some examples: --forecast=202001-202004, --forecast=jan-, --forecast=2020. Budgeting with periodic transactions- With the --budget flag, currently supported by the balance command,- each periodic transaction rule declares recurring budget goals for the- specified accounts. Eg the first example above declares a goal of- spending $2000 on rent (and also, a goal of depositing $2000 into- checking) every month. Goals and actual performance can then be com-+ With the --budget flag, currently supported by the balance command,+ each periodic transaction rule declares recurring budget goals for the+ specified accounts. Eg the first example above declares a goal of+ spending $2000 on rent (and also, a goal of depositing $2000 into+ checking) every month. Goals and actual performance can then be com- pared in budget reports. - For more details, see: balance: Budget report and Budgeting and Fore-+ For more details, see: balance: Budget report and Budgeting and Fore- casting. Auto postings- "Automated postings" or "auto postings" are extra postings which get- added automatically to transactions which match certain queries, de-+ "Automated postings" or "auto postings" are extra postings which get+ added automatically to transactions which match certain queries, de- fined by "auto posting rules", when you use the --auto flag. An auto posting rule looks a bit like a transaction:@@ -1357,27 +1362,27 @@ ... ACCOUNT [AMOUNT] - except the first line is an equals sign (mnemonic: = suggests match-- ing), followed by a query (which matches existing postings), and each- "posting" line describes a posting to be generated, and the posting+ except the first line is an equals sign (mnemonic: = suggests match-+ ing), followed by a query (which matches existing postings), and each+ "posting" line describes a posting to be generated, and the posting amounts can be: - o a normal amount with a commodity symbol, eg $2. This will be used+ o a normal amount with a commodity symbol, eg $2. This will be used as-is. o a number, eg 2. The commodity symbol (if any) from the matched post- ing will be added to this. - o a numeric multiplier, eg *2 (a star followed by a number N). The+ o a numeric multiplier, eg *2 (a star followed by a number N). The matched posting's amount (and total price, if any) will be multiplied by N. - o a multiplier with a commodity symbol, eg *$2 (a star, number N, and+ o a multiplier with a commodity symbol, eg *$2 (a star, number N, and symbol S). The matched posting's amount will be multiplied by N, and its commodity symbol will be replaced with S. - Any query term containing spaces must be enclosed in single or double- quotes, as on the command line. Eg, note the quotes around the second+ Any query term containing spaces must be enclosed in single or double+ quotes, as on the command line. Eg, note the quotes around the second query term below: = expenses:groceries 'expenses:dining out'@@ -1416,24 +1421,24 @@ Auto postings and multiple files An auto posting rule can affect any transaction in the current file, or- in any parent file or child file. Note, currently it will not affect+ in any parent file or child file. Note, currently it will not affect sibling files (when multiple -f/--file are used - see #1212). Auto postings and dates- A posting date (or secondary date) in the matched posting, or (taking- precedence) a posting date in the auto posting rule itself, will also+ A posting date (or secondary date) in the matched posting, or (taking+ precedence) a posting date in the auto posting rule itself, will also be used in the generated posting. Auto postings and transaction balancing / inferred amounts / balance asser- tions Currently, auto postings are added: - o after missing amounts are inferred, and transactions are checked for+ o after missing amounts are inferred, and transactions are checked for balancedness, o but before balance assertions are checked. - Note this means that journal entries must be balanced both before and+ Note this means that journal entries must be balanced both before and after auto postings are added. This changed in hledger 1.12+; see #893 for background. @@ -1443,11 +1448,11 @@ o generated-posting:= QUERY - shows this was generated by an auto post- ing rule, and the query - o _generated-posting:= QUERY - a hidden tag, which does not appear in+ o _generated-posting:= QUERY - a hidden tag, which does not appear in hledger's output. This can be used to match postings generated "just now", rather than generated in the past and saved to the journal. - Also, any transaction that has been changed by auto posting rules will+ Also, any transaction that has been changed by auto posting rules will have these tags added: o modified: - this transaction was modified@@ -1458,7 +1463,7 @@ REPORTING BUGS- Report bugs at http://bugs.hledger.org (or on the #hledger IRC channel+ Report bugs at http://bugs.hledger.org (or on the #hledger IRC channel or hledger mail list) @@ -1472,7 +1477,7 @@ SEE ALSO- hledger(1), hledger-ui(1), hledger-web(1), hledger-api(1),+ hledger(1), hledger-ui(1), hledger-web(1), hledger-api(1), hledger_csv(5), hledger_journal(5), hledger_timeclock(5), hledger_time- dot(5), ledger(1) @@ -1480,4 +1485,4 @@ -hledger 1.18 June 2020 hledger_journal(5)+hledger 1.18.1 June 2020 hledger_journal(5)
hledger_timeclock.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_timeclock" "5" "June 2020" "hledger 1.18" "hledger User Manuals"+.TH "hledger_timeclock" "5" "June 2020" "hledger 1.18.1" "hledger User Manuals"
hledger_timeclock.info view
@@ -4,8 +4,8 @@ File: hledger_timeclock.info, Node: Top, Up: (dir) -hledger_timeclock(5) hledger 1.18-*********************************+hledger_timeclock(5) hledger 1.18.1+*********************************** Timeclock - the time logging format of timeclock.el, as read by hledger
hledger_timeclock.txt view
@@ -78,4 +78,4 @@ -hledger 1.18 June 2020 hledger_timeclock(5)+hledger 1.18.1 June 2020 hledger_timeclock(5)
hledger_timedot.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_timedot" "5" "June 2020" "hledger 1.18" "hledger User Manuals"+.TH "hledger_timedot" "5" "June 2020" "hledger 1.18.1" "hledger User Manuals"
hledger_timedot.info view
@@ -4,8 +4,8 @@ File: hledger_timedot.info, Node: Top, Up: (dir) -hledger_timedot(5) hledger 1.18-*******************************+hledger_timedot(5) hledger 1.18.1+********************************* Timedot - hledger's human-friendly time logging format
hledger_timedot.txt view
@@ -161,4 +161,4 @@ -hledger 1.18 June 2020 hledger_timedot(5)+hledger 1.18.1 June 2020 hledger_timedot(5)