packages feed

hledger-lib 1.9 → 1.9.1

raw patch · 33 files changed

+1616/−980 lines, 33 filesdep +tabulardep ~base-compat

Dependencies added: tabular

Dependency ranges changed: base-compat

Files

CHANGES view
@@ -2,6 +2,18 @@ Most user-visible changes are noted in the hledger changelog, instead.  +# 1.9.1 (2018/4/30)++* new generic PeriodicReport, and some report-related type aliases++* new BudgetReport++* make (readJournal|tryReader)s?WithOpts the default api, dropping "WithOpts"++* automated postings and command line account aliases happen earlier+  in journal processing (see hledger changelog)++ # 1.9 (2018/3/31)  * support ghc 8.4, latest deps
Hledger/Data/AccountName.hs view
@@ -57,8 +57,24 @@ accountNameLevel "" = 0 accountNameLevel a = T.length (T.filter (==acctsepchar) a) + 1 +-- | A top-level account prefixed to some accounts in budget reports.+-- Defined here so it can be ignored by accountNameDrop. +unbudgetedAccountName :: T.Text+unbudgetedAccountName = "<unbudgeted>"++-- | Remove some number of account name components from the front of the account name.+-- If the special "<unbudgeted>" top-level account is present, it is preserved and+-- dropping affects the rest of the account name.  accountNameDrop :: Int -> AccountName -> AccountName-accountNameDrop n = accountNameFromComponents . drop n . accountNameComponents+accountNameDrop n a+  | a == unbudgetedAccountName = a+  | unbudgetedAccountAndSep `T.isPrefixOf` a =+      case accountNameDrop n $ T.drop (T.length unbudgetedAccountAndSep) a of+        "" -> unbudgetedAccountName+        a' -> unbudgetedAccountAndSep <> a'+  | otherwise = accountNameFromComponents $ drop n $ accountNameComponents a+  where +    unbudgetedAccountAndSep = unbudgetedAccountName <> acctsep  -- | Sorted unique account names implied by these account names, -- ie these plus all their parent accounts up to the root.
Hledger/Data/Amount.hs view
@@ -61,6 +61,7 @@   amountValue,   -- ** rendering   amountstyle,+  styleAmount,   showAmount,   cshowAmount,   showAmountWithZeroCommodity,@@ -93,6 +94,7 @@   isReallyZeroMixedAmountCost,   mixedAmountValue,   -- ** rendering+  styleMixedAmount,   showMixedAmount,   showMixedAmountOneLine,   showMixedAmountDebug,@@ -131,8 +133,14 @@  deriving instance Show MarketPrice ++-------------------------------------------------------------------------------+-- Amount styles++-- | Default amount style  amountstyle = AmountStyle L False 0 (Just '.') Nothing + ------------------------------------------------------------------------------- -- Amount @@ -265,6 +273,14 @@ showPriceDebug (UnitPrice pa)  = " @ "  ++ showAmountDebug pa showPriceDebug (TotalPrice pa) = " @@ " ++ showAmountDebug pa +-- | Given a map of standard amount display styles, apply the appropriate one to this amount.+-- If there's no standard style for this amount's commodity, return the amount unchanged.+styleAmount :: M.Map CommoditySymbol AmountStyle -> Amount -> Amount+styleAmount styles a =+  case M.lookup (acommodity a) styles of+    Just s  -> a{astyle=s}+    Nothing -> a + -- | Get the string representation of an amount, based on its -- commodity's display settings. String representations equivalent to -- zero are converted to just \"0\". The special "missing" amount is@@ -555,6 +571,10 @@ --     where a' = normaliseMixedAmountSquashPricesForDisplay a --           b' = normaliseMixedAmountSquashPricesForDisplay b +-- | Given a map of standard amount display styles, apply the appropriate ones to each individual amount.+styleMixedAmount :: M.Map CommoditySymbol AmountStyle -> MixedAmount -> MixedAmount+styleMixedAmount styles (Mixed as) = Mixed $ map (styleAmount styles) as + -- | Get the string representation of a mixed amount, after -- normalising it to one amount per commodity. Assumes amounts have -- no or similar prices, otherwise this can show misleading prices.@@ -647,6 +667,7 @@  mixedAmountValue :: Journal -> Day -> MixedAmount -> MixedAmount mixedAmountValue j d (Mixed as) = Mixed $ map (amountValue j d) as+  ------------------------------------------------------------------------------- -- misc
Hledger/Data/AutoTransaction.hs view
@@ -71,8 +71,9 @@ runModifierTransaction q mt = modifier where     q' = simplifyQuery $ And [q, mtvaluequery mt (error "query cannot depend on current time")]     mods = map runModifierPosting $ mtpostings mt-    generatePostings ps = [m p | p <- ps, q' `matchesPosting` p, m <- mods]-    modifier t@(tpostings -> ps) = t { tpostings = ps ++ generatePostings ps }+    generatePostings ps = [p' | p <- ps+                              , p' <- if q' `matchesPosting` p then p:[ m p | m <- mods] else [p]]+    modifier t@(tpostings -> ps) = t { tpostings = generatePostings ps }  -- | Extract 'Query' equivalent of 'mtvalueexpr' from 'ModifierTransaction' --
Hledger/Data/Journal.hs view
@@ -16,10 +16,10 @@   addModifierTransaction,   addPeriodicTransaction,   addTransaction,-  journalApplyAliases,   journalBalanceTransactions,   journalApplyCommodityStyles,   commodityStylesFromAmounts,+  journalCommodityStyles,   journalConvertAmountsToCost,   journalFinalise,   journalPivot,@@ -485,19 +485,6 @@  -} --- | Apply additional account aliases (eg from the command-line) to all postings in a journal.-journalApplyAliases :: [AccountAlias] -> Journal -> Journal-journalApplyAliases aliases j@Journal{jtxns=ts} =-  -- (if null aliases-  --  then id-  --  else (dbgtrace $-  --        "applying additional command-line aliases:\n"-  --        ++ chomp (unlines $ map (" "++) $ lines $ ppShow aliases))) $-  j{jtxns=map dotransaction ts}-    where-      dotransaction t@Transaction{tpostings=ps} = t{tpostings=map doposting ps}-      doposting p@Posting{paccount=a} = p{paccount= accountNameApplyAliases aliases a}- -- | Do post-parse processing on a parsed journal to make it ready for -- use.  Reverse parsed data to normal order, canonicalise amount -- formats, check/ensure that transactions are balanced, and maybe@@ -617,8 +604,11 @@   runExceptT $ do     bals <- lift $ HT.newSized size     txStore <- lift $ createStore-    flip R.runReaderT (Env bals (storeIn txStore) assrt $-                       Just $ jinferredcommodities j) $ do+    let env = Env bals +                  (storeIn txStore) +                  assrt+                  (Just $ journalCommodityStyles j)+    flip R.runReaderT env $ do       dated <- fmap snd . sortBy (comparing fst) . concat              <$> mapM' discriminateByDate (jtxns j)       mapM' checkInferAndRegisterAmounts dated@@ -738,7 +728,6 @@ liftModifier :: (Env s -> ST s a) -> CurrentBalancesModifier s a liftModifier f = R.ask >>= lift . lift . f - -- | Choose and apply a consistent display format to the posting -- amounts in each commodity. Each commodity's format is specified by -- a commodity format directive, or otherwise inferred from posting@@ -747,28 +736,20 @@ journalApplyCommodityStyles j@Journal{jtxns=ts, jmarketprices=mps} = j''     where       j' = journalInferCommodityStyles j+      styles = journalCommodityStyles j'       j'' = j'{jtxns=map fixtransaction ts, jmarketprices=map fixmarketprice mps}       fixtransaction t@Transaction{tpostings=ps} = t{tpostings=map fixposting ps}-      fixposting p@Posting{pamount=a} = p{pamount=fixmixedamount a}-      fixmarketprice mp@MarketPrice{mpamount=a} = mp{mpamount=fixamount a}-      fixmixedamount (Mixed as) = Mixed $ map fixamount as-      fixamount a@Amount{acommodity=c} = a{astyle=journalCommodityStyle j' c}---- | Get this journal's standard display style for the given--- commodity.  That is the style defined by the last corresponding--- commodity format directive if any, otherwise the style inferred--- from the posting amounts (or in some cases, price amounts) in this--- commodity if any, otherwise the default style.-journalCommodityStyle :: Journal -> CommoditySymbol -> AmountStyle-journalCommodityStyle j = fromMaybe amountstyle{asprecision=2} . journalCommodityStyleLookup j+      fixposting p@Posting{pamount=a} = p{pamount=styleMixedAmount styles a}+      fixmarketprice mp@MarketPrice{mpamount=a} = mp{mpamount=styleAmount styles a} -journalCommodityStyleLookup :: Journal -> CommoditySymbol -> Maybe AmountStyle-journalCommodityStyleLookup j c =-  listToMaybe $-  catMaybes [-     M.lookup c (jcommodities j) >>= cformat-    ,M.lookup c $ jinferredcommodities j-    ]+-- | Get all the amount styles defined in this journal, either +-- declared by a commodity directive (preferred) or inferred from amounts,+-- as a map from symbol to style. +journalCommodityStyles :: Journal -> M.Map CommoditySymbol AmountStyle+journalCommodityStyles j = declaredstyles <> inferredstyles+  where+    declaredstyles = M.mapMaybe cformat $ jcommodities j+    inferredstyles = jinferredcommodities j  -- | Infer a display format for each commodity based on the amounts parsed. -- "hledger... will use the format of the first posting amount in the@@ -776,8 +757,8 @@ journalInferCommodityStyles :: Journal -> Journal journalInferCommodityStyles j =   j{jinferredcommodities =-        commodityStylesFromAmounts $-        dbg8 "journalChooseCommmodityStyles using amounts" $ journalAmounts j}+    commodityStylesFromAmounts $+    dbg8 "journalInferCommmodityStyles using amounts" $ journalAmounts j}  -- | Given a list of amounts in parse order, build a map from their commodity names -- to standard commodity display formats.@@ -833,10 +814,8 @@       fixtransaction t@Transaction{tpostings=ps} = t{tpostings=map fixposting ps}       fixposting p@Posting{pamount=a} = p{pamount=fixmixedamount a}       fixmixedamount (Mixed as) = Mixed $ map fixamount as-      fixamount = applyJournalStyle . costOfAmount-      applyJournalStyle a-          | Just s <- journalCommodityStyleLookup j (acommodity a) = a{astyle=s}-          | otherwise = a+      fixamount = styleAmount styles . costOfAmount+      styles = journalCommodityStyles j  -- -- | Get this journal's unique, display-preference-canonicalised commodities, by symbol. -- journalCanonicalCommodities :: Journal -> M.Map String CommoditySymbol
Hledger/Data/Transaction.hs view
@@ -278,7 +278,7 @@     "inferBalancingAmount" ~: do     let p `gives` p' = assertEqual (show p) (Right p') $ inferTransaction p         inferTransaction :: Transaction -> Either String Transaction-        inferTransaction = runIdentity . runExceptT . inferBalancingAmount (\_ _ -> return ())+        inferTransaction = runIdentity . runExceptT . inferBalancingAmount (\_ _ -> return ()) Map.empty     nulltransaction `gives` nulltransaction     nulltransaction{       tpostings=[@@ -382,11 +382,11 @@      -- ^ update function   -> Maybe (Map.Map CommoditySymbol AmountStyle)   -> Transaction -> m Transaction-balanceTransactionUpdate update styles t =-  finalize =<< inferBalancingAmount update t+balanceTransactionUpdate update mstyles t =+  finalize =<< inferBalancingAmount update (fromMaybe Map.empty mstyles) t   where     finalize t' = let t'' = inferBalancingPrices t'-                  in if isTransactionBalanced styles t''+                  in if isTransactionBalanced mstyles t''                      then return $ txnTieKnot t''                      else throwError $ printerr $ nonzerobalanceerror t''     printerr s = intercalate "\n" [s, showTransactionUnelided t]@@ -409,11 +409,12 @@ -- We can infer a missing amount when there are multiple postings and exactly -- one of them is amountless. If the amounts had price(s) the inferred amount -- have the same price(s), and will be converted to the price commodity.-inferBalancingAmount :: MonadError String m-                     => (AccountName -> MixedAmount -> m ())-                     -- ^ update function-                     -> Transaction -> m Transaction-inferBalancingAmount update t@Transaction{tpostings=ps}+inferBalancingAmount :: MonadError String m =>+                        (AccountName -> MixedAmount -> m ()) -- ^ update function+                     -> Map.Map CommoditySymbol AmountStyle  -- ^ standard amount styles+                     -> Transaction+                     -> m Transaction+inferBalancingAmount update styles t@Transaction{tpostings=ps}   | length amountlessrealps > 1       = throwError $ printerr "could not balance this transaction - can't have more than one real posting with no amount (remember to put 2 or more spaces before amounts)"   | length amountlessbvps > 1@@ -432,8 +433,13 @@     inferamount p@Posting{ptype=BalancedVirtualPosting}      | not (hasAmount p) = updateAmount p bvsum     inferamount p = return p-    updateAmount p amt = update (paccount p) amt' >> return p { pamount=amt', porigin=Just $ originalPosting p }-      where amt' = normaliseMixedAmount $ costOfMixedAmount (-amt)+    updateAmount p amt = +      update (paccount p) amt' >> return p { pamount=amt', porigin=Just $ originalPosting p }+      where+        -- Inferred amounts are converted to cost.+        -- Also, ensure the new amount has the standard style for its commodity  +        -- (the main amount styling pass happened before this balancing pass).   +        amt' = styleMixedAmount styles $ normaliseMixedAmount $ costOfMixedAmount (-amt)  -- | Infer prices for this transaction's posting amounts, if needed to make -- the postings balance, and if possible. This is done once for the real
Hledger/Data/Types.hs view
@@ -22,7 +22,6 @@  import GHC.Generics (Generic) import Control.DeepSeq (NFData)-import Control.Monad.Except (ExceptT) import Data.Data import Data.Decimal import Data.Default@@ -303,7 +302,7 @@   -- principal data   ,jaccounts              :: [(AccountName, Maybe AccountCode)]     -- ^ accounts that have been declared by account directives   ,jcommodities           :: M.Map CommoditySymbol Commodity        -- ^ commodities and formats declared by commodity directives-  ,jinferredcommodities   :: M.Map CommoditySymbol AmountStyle      -- ^ commodities and formats inferred from journal amounts+  ,jinferredcommodities   :: M.Map CommoditySymbol AmountStyle      -- ^ commodities and formats inferred from journal amounts  XXX misnamed   ,jmarketprices          :: [MarketPrice]   ,jmodifiertxns          :: [ModifierTransaction]   ,jperiodictxns          :: [PeriodicTransaction]@@ -328,28 +327,6 @@ -- | The id of a data format understood by hledger, eg @journal@ or @csv@. -- The --output-format option selects one of these for output. type StorageFormat = String---- | A hledger journal reader is a triple of storage format name, a--- detector of that format, and a parser from that format to Journal.-data Reader = Reader {--     -- The canonical name of the format handled by this reader-     rFormat   :: StorageFormat--     -- The file extensions recognised as containing this format-    ,rExtensions :: [String]--     -- A text parser for this format, accepting an optional rules file,-     -- assertion-checking flag, and file path for error messages,-     -- producing an exception-raising IO action that returns a journal-     -- or error message.-    ,rParser   :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal--     -- Experimental readers are never tried automatically.-    ,rExperimental :: Bool-    }--instance Show Reader where show r = rFormat r ++ " reader"  -- | An account, with name, balances and links to parent/subaccounts -- which let you walk up or down the account tree.
Hledger/Read.hs view
@@ -14,7 +14,6 @@   PrefixedFilePath,   defaultJournal,   defaultJournalPath,-  readJournalFilesWithOpts,   readJournalFiles,   readJournalFile,   requireJournalFileExists,@@ -26,7 +25,6 @@   readJournal',    -- * Re-exported-  JournalReader.accountaliasp,   JournalReader.postingp,   module Hledger.Read.Common, @@ -36,10 +34,10 @@  ) where -import Control.Applicative ((<|>)) import Control.Arrow (right) import qualified Control.Exception as C import Control.Monad.Except+import Data.Default import Data.List import Data.Maybe import Data.Ord@@ -90,7 +88,7 @@  -- | Read the default journal file specified by the environment, or raise an error. defaultJournal :: IO Journal-defaultJournal = defaultJournalPath >>= readJournalFile Nothing Nothing True >>= either error' return+defaultJournal = defaultJournalPath >>= readJournalFile def >>= either error' return  -- | Get the default journal file path specified by the environment. -- Like ledger, we look first for the LEDGER_FILE environment@@ -112,52 +110,6 @@                   home <- getHomeDirectory `C.catch` (\(_::C.IOException) -> return "")                   return $ home </> journalDefaultFilename --- | @readJournalFiles mformat mrulesfile assrt prefixedfiles@------ Read a Journal from each specified file path and combine them into one.--- Or, return the first error message.------ Combining Journals means concatenating them, basically.--- The parse state resets at the start of each file, which means that--- directives & aliases do not cross file boundaries.--- (The final parse state saved in the Journal does span all files, however.)------ As with readJournalFile,--- file paths can optionally have a READER: prefix,--- and the @mformat@, @mrulesfile, and @assrt@ arguments are supported--- (and these are applied to all files).----readJournalFiles :: Maybe StorageFormat -> Maybe FilePath -> Bool -> [PrefixedFilePath] -> IO (Either String Journal)-readJournalFiles mformat mrulesfile assrt prefixedfiles = do-  (right mconcat1 . sequence)-    <$> mapM (readJournalFile mformat mrulesfile assrt) prefixedfiles-  where mconcat1 :: Monoid t => [t] -> t-        mconcat1 [] = mempty-        mconcat1 x = foldr1 mappend x---- | @readJournalFile mformat mrulesfile assrt prefixedfile@------ Read a Journal from this file, or from stdin if the file path is -,--- or return an error message. The file path can have a READER: prefix.------ The reader (data format) is chosen based on (in priority order):--- the @mformat@ argument;--- the file path's READER: prefix, if any;--- a recognised file name extension (in readJournal);--- if none of these identify a known reader, all built-in readers are tried in turn.------ A CSV conversion rules file (@mrulesfiles@) can be specified to help convert CSV data.------ Optionally, any balance assertions in the journal can be checked (@assrt@).----readJournalFile :: Maybe StorageFormat -> Maybe FilePath -> Bool -> PrefixedFilePath -> IO (Either String Journal)-readJournalFile mformat mrulesfile assrt prefixedfile = do-  let-    (mprefixformat, f) = splitReaderPrefix prefixedfile-    mfmt = mformat <|> mprefixformat-  requireJournalFileExists f-  readFileOrStdinPortably f >>= readJournal mfmt mrulesfile assrt (Just f)- -- | If a filepath is prefixed by one of the reader names and a colon, -- split that off. Eg "csv:-" -> (Just "csv", "-"). splitReaderPrefix :: PrefixedFilePath -> (Maybe String, FilePath)@@ -195,7 +147,7 @@  -- | Read a Journal from the given text trying all readers in turn, or throw an error. readJournal' :: Text -> IO Journal-readJournal' t = readJournal Nothing Nothing True Nothing t >>= either error' return+readJournal' t = readJournal def Nothing t >>= either error' return  tests_readJournal' = [   "readJournal' parses sample journal" ~: do@@ -203,28 +155,6 @@      assertBool "" True  ] --- | @readJournal mformat mrulesfile assrt mfile txt@------ Read a Journal from some text, or return an error message.------ The reader (data format) is chosen based on (in priority order):--- the @mformat@ argument;--- a recognised file name extension in @mfile@ (if provided).--- If none of these identify a known reader, all built-in readers are tried in turn--- (returning the first one's error message if none of them succeed).------ A CSV conversion rules file (@mrulesfiles@) can be specified to help convert CSV data.------ Optionally, any balance assertions in the journal can be checked (@assrt@).----readJournal :: Maybe StorageFormat -> Maybe FilePath -> Bool -> Maybe FilePath -> Text -> IO (Either String Journal)-readJournal mformat mrulesfile assrt mfile txt =-  let-    stablereaders = filter (not.rExperimental) readers-    rs = maybe stablereaders (:[]) $ findReader mformat mfile-  in-    tryReaders rs mrulesfile assrt mfile txt- -- | @findReader mformat mpath@ -- -- Find the reader named by @mformat@, if provided.@@ -241,43 +171,41 @@     (prefix,path') = splitReaderPrefix path     ext            = drop 1 $ takeExtension path' --- | @tryReaders readers mrulesfile assrt path t@+-- | Read a Journal from each specified file path and combine them into one.+-- Or, return the first error message. ----- Try to parse the given text to a Journal using each reader in turn,--- returning the first success, or if all of them fail, the first error message.-tryReaders :: [Reader] -> Maybe FilePath -> Bool -> Maybe FilePath -> Text -> IO (Either String Journal)-tryReaders readers mrulesfile assrt path t = firstSuccessOrFirstError [] readers-  where-    firstSuccessOrFirstError :: [String] -> [Reader] -> IO (Either String Journal)-    firstSuccessOrFirstError [] []        = return $ Left "no readers found"-    firstSuccessOrFirstError errs (r:rs) = do-      dbg1IO "trying reader" (rFormat r)-      result <- (runExceptT . (rParser r) mrulesfile assrt path') t-      dbg1IO "reader result" $ either id show result-      case result of Right j -> return $ Right j                        -- success!-                     Left e  -> firstSuccessOrFirstError (errs++[e]) rs -- keep trying-    firstSuccessOrFirstError (e:_) []    = return $ Left e              -- none left, return first error-    path' = fromMaybe "(string)" path------ New versions of readJournal* with easier arguments, and support for --new.--readJournalFilesWithOpts :: InputOpts -> [FilePath] -> IO (Either String Journal)-readJournalFilesWithOpts iopts =-  (right mconcat1 . sequence <$>) . mapM (readJournalFileWithOpts iopts)+-- Combining Journals means concatenating them, basically.+-- The parse state resets at the start of each file, which means that+-- directives & aliases do not affect subsequent sibling or parent files.+-- They do affect included child files though. +-- Also the final parse state saved in the Journal does span all files.+readJournalFiles :: InputOpts -> [FilePath] -> IO (Either String Journal)+readJournalFiles iopts =+  (right mconcat1 . sequence <$>) . mapM (readJournalFile iopts)   where     mconcat1 :: Monoid t => [t] -> t     mconcat1 [] = mempty     mconcat1 x  = foldr1 mappend x -readJournalFileWithOpts :: InputOpts -> PrefixedFilePath -> IO (Either String Journal)-readJournalFileWithOpts iopts prefixedfile = do+-- | Read a Journal from this file, or from stdin if the file path is -,+-- or return an error message. The file path can have a READER: prefix.+--+-- The reader (data format) to use is determined from (in priority order):+-- the @mformat_@ specified in the input options, if any;+-- the file path's READER: prefix, if any;+-- a recognised file name extension.+-- if none of these identify a known reader, all built-in readers are tried in turn.+--+-- The input options can also configure balance assertion checking, automated posting+-- generation, a rules file for converting CSV data, etc.+readJournalFile :: InputOpts -> PrefixedFilePath -> IO (Either String Journal)+readJournalFile iopts prefixedfile = do   let      (mfmt, f) = splitReaderPrefix prefixedfile     iopts' = iopts{mformat_=firstJust [mfmt, mformat_ iopts]}   requireJournalFileExists f   t <- readFileOrStdinPortably f-  ej <- readJournalWithOpts iopts' (Just f) t+  ej <- readJournal iopts' (Just f) t   case ej of     Left e  -> return $ Left e     Right j | new_ iopts -> do@@ -342,21 +270,40 @@     j'                    = j{jtxns=newsamedatets++laterts}     ds'                   = latestDates $ map tdate $ samedatets++laterts -readJournalWithOpts :: InputOpts -> Maybe FilePath -> Text -> IO (Either String Journal)-readJournalWithOpts iopts mfile txt =-  tryReadersWithOpts iopts mfile specifiedorallreaders txt+-- | @readJournal iopts mfile txt@+--+-- Read a Journal from some text, or return an error message.+--+-- The reader (data format) is chosen based on a recognised file name extension in @mfile@ (if provided).+-- If it does not identify a known reader, all built-in readers are tried in turn+-- (returning the first one's error message if none of them succeed).+--+-- Input ioptions (@iopts@) specify CSV conversion rules file to help convert CSV data,+-- enable or disable balance assertion checking and automated posting generation.+--+readJournal :: InputOpts -> Maybe FilePath -> Text -> IO (Either String Journal)+readJournal iopts mfile txt =+  tryReaders iopts mfile specifiedorallreaders txt   where     specifiedorallreaders = maybe stablereaders (:[]) $ findReader (mformat_ iopts) mfile     stablereaders = filter (not.rExperimental) readers -tryReadersWithOpts :: InputOpts -> Maybe FilePath -> [Reader] -> Text -> IO (Either String Journal)-tryReadersWithOpts iopts mpath readers txt = firstSuccessOrFirstError [] readers+-- | @tryReaders iopts readers path t@+--+-- Try to parse the given text to a Journal using each reader in turn,+-- returning the first success, or if all of them fail, the first error message.+--    +-- Input ioptions (@iopts@) specify CSV conversion rules file to help convert CSV data,+-- enable or disable balance assertion checking and automated posting generation.+--+tryReaders :: InputOpts -> Maybe FilePath -> [Reader] -> Text -> IO (Either String Journal)+tryReaders iopts mpath readers txt = firstSuccessOrFirstError [] readers   where     firstSuccessOrFirstError :: [String] -> [Reader] -> IO (Either String Journal)     firstSuccessOrFirstError [] []        = return $ Left "no readers found"     firstSuccessOrFirstError errs (r:rs) = do       dbg1IO "trying reader" (rFormat r)-      result <- (runExceptT . (rParser r) (mrules_file_ iopts) (not $ ignore_assertions_ iopts) path) txt+      result <- (runExceptT . (rParser r) iopts path) txt       dbg1IO "reader result" $ either id show result       case result of Right j -> return $ Right j                        -- success!                      Left e  -> firstSuccessOrFirstError (errs++[e]) rs -- keep trying@@ -408,7 +355,7 @@    "journal" ~: do     r <- runExceptT $ parseWithState mempty JournalReader.journalp ""     assertBool "journalp should parse an empty file" (isRight $ r)-    jE <- readJournal Nothing Nothing True Nothing "" -- don't know how to get it from journal+    jE <- readJournal def Nothing "" -- don't know how to get it from journal     either error' (assertBool "journalp parsing an empty file should give an empty journal" . null . jtxns) jE    ]
Hledger/Read/Common.hs view
@@ -47,7 +47,29 @@  import Hledger.Data import Hledger.Utils+import qualified Hledger.Query as Q (Query(Any)) +-- | A hledger journal reader is a triple of storage format name, a+-- detector of that format, and a parser from that format to Journal.+data Reader = Reader {++     -- The canonical name of the format handled by this reader+     rFormat   :: StorageFormat++     -- The file extensions recognised as containing this format+    ,rExtensions :: [String]++     -- A text parser for this format, accepting input options, file+     -- path for error messages and file contents, producing an exception-raising IO+     -- action that returns a journal or error message.+    ,rParser   :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal++     -- Experimental readers are never tried automatically.+    ,rExperimental :: Bool+    }++instance Show Reader where show r = rFormat r ++ " reader"+ -- $setup  -- | Various options to use when reading journal files.@@ -63,12 +85,13 @@     ,new_               :: Bool                 -- ^ read only new transactions since this file was last read     ,new_save_          :: Bool                 -- ^ save latest new transactions state for next time     ,pivot_             :: String               -- ^ use the given field's value as the account name +    ,auto_              :: Bool                 -- ^ generate automatic postings when journal is parsed       } deriving (Show, Data) --, Typeable)  instance Default InputOpts where def = definputopts  definputopts :: InputOpts-definputopts = InputOpts def def def def def def True def+definputopts = InputOpts def def def def def def True def def  rawOptsToInputOpts :: RawOpts -> InputOpts rawOptsToInputOpts rawopts = InputOpts{@@ -81,6 +104,7 @@   ,new_               = boolopt "new" rawopts   ,new_save_          = True   ,pivot_             = stringopt "pivot" rawopts+  ,auto_              = boolopt "auto" rawopts                           }  --- * parsing utils@@ -115,27 +139,40 @@             | otherwise = unPos $ sourceLine p' -- might be at end of file withat last new-line  --- | Given a megaparsec ParsedJournal parser, balance assertion flag, file+-- | Generate Automatic postings and add them to the current journal.+generateAutomaticPostings :: Journal -> Journal+generateAutomaticPostings j = j { jtxns = map modifier $ jtxns j }+  where+    modifier = foldr (flip (.) . runModifierTransaction') id mtxns+    runModifierTransaction' = fmap txnTieKnot . runModifierTransaction Q.Any+    mtxns = jmodifiertxns j++-- | Given a megaparsec ParsedJournal parser, input options, file -- path and file content: parse and post-process a Journal, or give an error.-parseAndFinaliseJournal :: ErroringJournalParser IO ParsedJournal -> Bool-                        -> FilePath -> Text -> ExceptT String IO Journal-parseAndFinaliseJournal parser assrt f txt = do+parseAndFinaliseJournal :: ErroringJournalParser IO ParsedJournal -> InputOpts+                           -> FilePath -> Text -> ExceptT String IO Journal+parseAndFinaliseJournal parser iopts f txt = do   t <- liftIO getClockTime   y <- liftIO getCurrentYear   ep <- runParserT (evalStateT parser nulljournal {jparsedefaultyear=Just y}) f txt   case ep of-    Right pj -> case journalFinalise t f txt assrt pj of+    Right pj -> +      let pj' = if auto_ iopts then generateAutomaticPostings pj else pj in+      case journalFinalise t f txt (not $ ignore_assertions_ iopts) pj' of                         Right j -> return j                         Left e  -> throwError e     Left e   -> throwError $ parseErrorPretty e -parseAndFinaliseJournal' :: JournalParser Identity ParsedJournal -> Bool -> FilePath -> Text -> ExceptT String IO Journal-parseAndFinaliseJournal' parser assrt f txt = do+parseAndFinaliseJournal' :: JournalParser Identity ParsedJournal -> InputOpts +                            -> FilePath -> Text -> ExceptT String IO Journal+parseAndFinaliseJournal' parser iopts f txt = do   t <- liftIO getClockTime   y <- liftIO getCurrentYear   let ep = runParser (evalStateT parser nulljournal {jparsedefaultyear=Just y}) f txt   case ep of-    Right pj -> case journalFinalise t f txt assrt pj of+    Right pj -> +      let pj' = if auto_ iopts then generateAutomaticPostings pj else pj in      +      case journalFinalise t f txt (not $ ignore_assertions_ iopts) pj' of                         Right j -> return j                         Left e  -> throwError e     Left e   -> throwError $ parseErrorPretty e
Hledger/Read/CsvReader.hs view
@@ -60,7 +60,7 @@ import Hledger.Data import Hledger.Utils.UTF8IOCompat (getContents) import Hledger.Utils-import Hledger.Read.Common (amountp, statusp, genericSourcePos)+import Hledger.Read.Common (Reader(..),InputOpts(..),amountp, statusp, genericSourcePos)   reader :: Reader@@ -73,8 +73,9 @@  -- | Parse and post-process a "Journal" from CSV data, or give an error. -- XXX currently ignores the string and reads from the file path-parse :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal-parse rulesfile _ f t = do+parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal+parse iopts f t = do+  let rulesfile = mrules_file_ iopts   r <- liftIO $ readJournalFromCsv rulesfile f t   case r of Left e -> throwError e             Right j -> return $ journalNumberAndTieTransactions j@@ -725,10 +726,26 @@ type CsvAmountString = String  -- | Canonicalise the sign in a CSV amount string.--- Such strings can be parenthesized, which is equivalent to having a minus sign.--- Also they can end up with a double minus sign, which cancels out.+-- Such strings can have a minus sign, negating parentheses, +-- or any two of these (which cancels out).+--+-- >>> simplifySign "1"+-- "1"+-- >>> simplifySign "-1"+-- "-1"+-- >>> simplifySign "(1)"+-- "-1"+-- >>> simplifySign "--1"+-- "1"+-- >>> simplifySign "-(1)"+-- "1"+-- >>> simplifySign "(-1)"+-- "1"+-- >>> simplifySign "((1))"+-- "1" simplifySign :: CsvAmountString -> CsvAmountString simplifySign ('(':s) | lastMay s == Just ')' = simplifySign $ negateStr $ init s+simplifySign ('-':'(':s) | lastMay s == Just ')' = simplifySign $ init s simplifySign ('-':'-':s) = s simplifySign s = s 
Hledger/Read/JournalReader.hs view
@@ -63,8 +63,7 @@   -- numberp,   statusp,   emptyorcommentlinep,-  followingcommentp,-  accountaliasp+  followingcommentp    -- * Tests   ,tests_Hledger_Read_JournalReader@@ -119,8 +118,18 @@  -- | Parse and post-process a "Journal" from hledger's journal file -- format, or give an error.-parse :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal-parse _ = parseAndFinaliseJournal journalp+parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal+parse iopts = parseAndFinaliseJournal journalp' iopts+  where+    journalp' = do +      -- reverse parsed aliases to ensure that they are applied in order given on commandline+      mapM_ addAccountAlias (reverse $ aliasesFromOpts iopts) +      journalp++-- | Get the account name aliases from options, if any.+aliasesFromOpts :: InputOpts -> [AccountAlias]+aliasesFromOpts = map (\a -> fromparse $ runParser accountaliasp ("--alias "++quoteIfNeeded a) $ T.pack a)+                  . aliases_  --- * parsers --- ** journal
Hledger/Read/TimeclockReader.hs view
@@ -79,8 +79,8 @@ -- | Parse and post-process a "Journal" from timeclock.el's timeclock -- format, saving the provided file path and the current time, or give an -- error.-parse :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal-parse _ = parseAndFinaliseJournal timeclockfilep+parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal+parse = parseAndFinaliseJournal timeclockfilep  timeclockfilep :: ErroringJournalParser IO ParsedJournal timeclockfilep = do many timeclockitemp
Hledger/Read/TimedotReader.hs view
@@ -65,8 +65,8 @@   }  -- | Parse and post-process a "Journal" from the timedot format, or give an error.-parse :: Maybe FilePath -> Bool -> FilePath -> Text -> ExceptT String IO Journal-parse _ = parseAndFinaliseJournal timedotfilep+parse :: InputOpts -> FilePath -> Text -> ExceptT String IO Journal+parse = parseAndFinaliseJournal timedotfilep  timedotfilep :: JournalParser m ParsedJournal timedotfilep = do many timedotfileitemp
Hledger/Reports.hs view
@@ -10,11 +10,13 @@  module Hledger.Reports (   module Hledger.Reports.ReportOptions,+  module Hledger.Reports.ReportTypes,   module Hledger.Reports.EntriesReport,   module Hledger.Reports.PostingsReport,   module Hledger.Reports.TransactionsReports,   module Hledger.Reports.BalanceReport,   module Hledger.Reports.MultiBalanceReports,+  module Hledger.Reports.BudgetReport, --   module Hledger.Reports.BalanceHistoryReport,    -- * Tests@@ -25,11 +27,13 @@ import Test.HUnit  import Hledger.Reports.ReportOptions+import Hledger.Reports.ReportTypes import Hledger.Reports.EntriesReport import Hledger.Reports.PostingsReport import Hledger.Reports.TransactionsReports import Hledger.Reports.BalanceReport import Hledger.Reports.MultiBalanceReports+import Hledger.Reports.BudgetReport -- import Hledger.Reports.BalanceHistoryReport  tests_Hledger_Reports :: Test@@ -40,5 +44,6 @@  tests_Hledger_Reports_EntriesReport,  tests_Hledger_Reports_PostingsReport,  tests_Hledger_Reports_BalanceReport,- tests_Hledger_Reports_MultiBalanceReport+ tests_Hledger_Reports_MultiBalanceReport,+ tests_Hledger_Reports_BudgetReport  ]
Hledger/Reports/BalanceReport.hs view
@@ -350,7 +350,7 @@      ]      ,"accounts report with cost basis" ~: do-       j <- (readJournal Nothing Nothing Nothing $ unlines+       j <- (readJournal def Nothing $ unlines               [""               ,"2008/1/1 test           "               ,"  a:b          10h @ $50"
+ Hledger/Reports/BudgetReport.hs view
@@ -0,0 +1,361 @@+{- |+-}++{-# LANGUAGE CPP #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE ScopedTypeVariables #-}++module Hledger.Reports.BudgetReport+where++import Data.Decimal+import Data.List+import Data.Maybe+#if !(MIN_VERSION_base(4,11,0))+import Data.Monoid ((<>))+#endif+import Data.Ord+import Data.Time.Calendar+import Safe+import Test.HUnit+--import Data.List+--import Data.Maybe+import qualified Data.Map as Map+import Data.Map (Map)+import qualified Data.Text as T+--import qualified Data.Text.Lazy as TL+--import System.Console.CmdArgs.Explicit as C+--import Lucid as L+--import Text.CSV+--import Test.HUnit+import Text.Printf (printf)+import Text.Tabular as T+--import Text.Tabular.AsciiWide++import Hledger.Data+--import Hledger.Query+import Hledger.Utils+--import Hledger.Read (mamountp')+import Hledger.Reports.ReportOptions+import Hledger.Reports.ReportTypes+import Hledger.Reports.MultiBalanceReports+++--type MultiBalanceReportRow    = (AccountName, AccountName, Int, [MixedAmount], MixedAmount, MixedAmount)+--type MultiBalanceReportTotals = ([MixedAmount], MixedAmount, MixedAmount) -- (Totals list, sum of totals, average of totals)++--type PeriodicReportRow a =+--  ( AccountName  -- ^ A full account name.+--  , [a]          -- ^ The data value for each subperiod.+--  , a            -- ^ The total of this row's values.+--  , a            -- ^ The average of this row's values.+--  )++type BudgetGoal    = Change+type BudgetTotal   = Total+type BudgetAverage = Average++-- | A budget report tracks expected and actual changes per account and subperiod.+type BudgetReport = PeriodicReport (Maybe Change, Maybe BudgetGoal)++-- | Calculate budget goals from all periodic transactions,+-- actual balance changes from the regular transactions,+-- and compare these to get a 'BudgetReport'.+-- Unbudgeted accounts may be hidden or renamed (see budgetRollup).+budgetReport :: ReportOpts -> Bool -> Bool -> DateSpan -> Day -> Journal -> BudgetReport+budgetReport ropts assrt showunbudgeted reportspan d j =+  let+    q = queryFromOpts d ropts +    budgetedaccts = +      dbg2 "budgetedacctsinperiod" $+      accountNamesFromPostings $ +      concatMap tpostings $ +      concatMap (flip runPeriodicTransaction reportspan) $ +      jperiodictxns j+    actualj = dbg1 "actualj" $ budgetRollUp budgetedaccts showunbudgeted j+    budgetj = dbg1 "budgetj" $ budgetJournal assrt ropts reportspan j+    actualreport@(MultiBalanceReport (actualspans, _, _)) = dbg1 "actualreport" $ multiBalanceReport ropts  q actualj+    budgetgoalreport@(MultiBalanceReport (_, budgetgoalitems, budgetgoaltotals)) = dbg1 "budgetgoalreport" $ multiBalanceReport ropts q budgetj+    budgetgoalreport'+      -- If no interval is specified:+      -- budgetgoalreport's span might be shorter actualreport's due to periodic txns; +      -- it should be safe to replace it with the latter, so they combine well. +      | interval_ ropts == NoInterval = MultiBalanceReport (actualspans, budgetgoalitems, budgetgoaltotals)+      | otherwise = budgetgoalreport +  in+    dbg1 "budgetreport" $ combineBudgetAndActual budgetgoalreport' actualreport++-- | Use all periodic transactions in the journal to generate +-- budget transactions in the specified report period.+-- Budget transactions are similar to forecast transactions except+-- their purpose is to set goal amounts (of change) per account and period.+budgetJournal :: Bool -> ReportOpts -> DateSpan -> Journal -> Journal+budgetJournal assrt _ropts reportspan j =+  either error' id $ journalBalanceTransactions assrt j{ jtxns = budgetts }+  where+    budgetspan = dbg2 "budgetspan" $ reportspan+    budgetts =+      dbg1 "budgetts" $+      [makeBudgetTxn t+      | pt <- jperiodictxns j+      , t <- runPeriodicTransaction pt budgetspan+      ]+    makeBudgetTxn t = txnTieKnot $ t { tdescription = T.pack "Budget transaction" }++-- | Adjust a journal's account names for budget reporting, in two ways:+--+-- 1. accounts with no budget goal anywhere in their ancestry are moved +--    under the "unbudgeted" top level account.+--+-- 2. subaccounts with no budget goal are merged with their closest parent account+--    with a budget goal, so that only budgeted accounts are shown. +--    This can be disabled by --show-unbudgeted.+--+budgetRollUp :: [AccountName] -> Bool -> Journal -> Journal+budgetRollUp budgetedaccts showunbudgeted j = j { jtxns = remapTxn <$> jtxns j }+  where+    remapTxn = mapPostings (map remapPosting)+      where+        mapPostings f t = txnTieKnot $ t { tpostings = f $ tpostings t }+        remapPosting p = p { paccount = remapAccount $ paccount p, porigin = Just . fromMaybe p $ porigin p }+          where+            remapAccount a+              | hasbudget         = a+              | hasbudgetedparent = if showunbudgeted then a else budgetedparent +              | otherwise         = if showunbudgeted then u <> acctsep <> a else u+              where+                hasbudget = a `elem` budgetedaccts+                hasbudgetedparent = not $ T.null budgetedparent+                budgetedparent = headDef "" $ filter (`elem` budgetedaccts) $ parentAccountNames a+                u = unbudgetedAccountName++-- | Combine a per-account-and-subperiod report of budget goals, and one+-- of actual change amounts, into a budget performance report.+-- The two reports should have the same report interval, but need not+-- have exactly the same account rows or date columns.+-- (Cells in the combined budget report can be missing a budget goal,+-- an actual amount, or both.) The combined report will include:+--+-- - consecutive subperiods at the same interval as the two reports,+--   spanning the period of both reports+--+-- - all accounts mentioned in either report, sorted by account code or+--   account name or amount as appropriate.+--+combineBudgetAndActual :: MultiBalanceReport -> MultiBalanceReport -> BudgetReport+combineBudgetAndActual+  (MultiBalanceReport (budgetperiods, budgetrows, (budgettots, budgetgrandtot, budgetgrandavg)))+  (MultiBalanceReport (actualperiods, actualrows, (actualtots, actualgrandtot, actualgrandavg))) =+  let+    periods = nub $ sort $ filter (/= nulldatespan) $ budgetperiods ++ actualperiods++    -- first, combine any corresponding budget goals with actual changes+    rows1 =+      [ (acct, treeacct, treeindent, amtandgoals, totamtandgoal, avgamtandgoal)+      | (acct, treeacct, treeindent, actualamts, actualtot, actualavg) <- actualrows+      , let mbudgetgoals       = Map.lookup acct budgetGoalsByAcct :: Maybe ([BudgetGoal], BudgetTotal, BudgetAverage)+      , let budgetmamts        = maybe (replicate (length periods) Nothing) (map Just . first3) mbudgetgoals :: [Maybe BudgetGoal]+      , let mbudgettot         = maybe Nothing (Just . second3) mbudgetgoals :: Maybe BudgetTotal+      , let mbudgetavg         = maybe Nothing (Just . third3)  mbudgetgoals :: Maybe BudgetAverage+      , let acctBudgetByPeriod = Map.fromList [ (p,budgetamt) | (p, Just budgetamt) <- zip budgetperiods budgetmamts ] :: Map DateSpan BudgetGoal+      , let acctActualByPeriod = Map.fromList [ (p,actualamt) | (p, Just actualamt) <- zip actualperiods (map Just actualamts) ] :: Map DateSpan Change+      , let amtandgoals        = [ (Map.lookup p acctActualByPeriod, Map.lookup p acctBudgetByPeriod) | p <- periods ] :: [(Maybe Change, Maybe BudgetGoal)]+      , let totamtandgoal      = (Just actualtot, mbudgettot)+      , let avgamtandgoal      = (Just actualavg, mbudgetavg)+      ]+      where+        budgetGoalsByAcct :: Map AccountName ([BudgetGoal], BudgetTotal, BudgetAverage) =+          Map.fromList [ (acct, (amts, tot, avg)) | (acct, _, _, amts, tot, avg) <- budgetrows ]++    -- next, make rows for budget goals with no actual changes+    rows2 =+      [ (acct, treeacct, treeindent, amtandgoals, totamtandgoal, avgamtandgoal)+      | (acct, treeacct, treeindent, budgetgoals, budgettot, budgetavg) <- budgetrows+      , not $ acct `elem` acctsdone+      , let acctBudgetByPeriod = Map.fromList $ zip budgetperiods budgetgoals :: Map DateSpan BudgetGoal+      , let amtandgoals        = [ (Nothing, Map.lookup p acctBudgetByPeriod) | p <- periods ] :: [(Maybe Change, Maybe BudgetGoal)]+      , let totamtandgoal      = (Nothing, Just budgettot)+      , let avgamtandgoal      = (Nothing, Just budgetavg)+      ]+      where+        acctsdone = map first6 rows1++    -- combine and re-sort rows+    -- TODO: respect hierarchy in tree mode+    -- TODO: respect --sort-amount+    -- TODO: add --sort-budget to sort by budget goal amount+    rows :: [PeriodicReportRow (Maybe Change, Maybe BudgetGoal)] =+      sortBy (comparing first6) $ rows1 ++ rows2+-- massive duplication from multiBalanceReport to handle tree mode sorting ?+--      dbg1 "sorteditems" $+--      sortitems items+--      where+--        sortitems+--          | sort_amount_ opts && accountlistmode_ opts == ALTree       = sortTreeMultiBalanceReportRowsByAmount+--          | sort_amount_ opts                                          = sortFlatMultiBalanceReportRowsByAmount+--          | not (sort_amount_ opts) && accountlistmode_ opts == ALTree = sortTreeMultiBalanceReportRowsByAccountCodeAndName+--          | otherwise                                                  = sortFlatMultiBalanceReportRowsByAccountCodeAndName+--          where+--            -- Sort the report rows, representing a flat account list, by row total.+--            sortFlatMultiBalanceReportRowsByAmount = sortBy (maybeflip $ comparing fifth6)+--              where+--                maybeflip = if normalbalance_ opts == Just NormallyNegative then id else flip+--+--            -- Sort the report rows, representing a tree of accounts, by row total at each level.+--            -- To do this we recreate an Account tree with the row totals as balances,+--            -- so we can do a hierarchical sort, flatten again, and then reorder the+--            -- report rows similarly. Yes this is pretty long winded.+--            sortTreeMultiBalanceReportRowsByAmount rows = sortedrows+--              where+--                anamesandrows = [(first6 r, r) | r <- rows]+--                anames = map fst anamesandrows+--                atotals = [(a,tot) | (a,_,_,_,tot,_) <- rows]+--                nametree = treeFromPaths $ map expandAccountName anames+--                accounttree = nameTreeToAccount "root" nametree+--                accounttreewithbals = mapAccounts setibalance accounttree+--                  where+--                    -- this error should not happen, but it's ugly TODO+--                    setibalance a = a{aibalance=fromMaybe (error "sortTreeMultiBalanceReportRowsByAmount 1") $ lookup (aname a) atotals}+--                sortedaccounttree = sortAccountTreeByAmount (fromMaybe NormallyPositive $ normalbalance_ opts) accounttreewithbals+--                sortedaccounts = drop 1 $ flattenAccounts sortedaccounttree+--                -- dropped the root account, also ignore any parent accounts not in rows+--                sortedrows = concatMap (\a -> maybe [] (:[]) $ lookup (aname a) anamesandrows) sortedaccounts+--+--            -- Sort the report rows by account code if any, with the empty account code coming last, then account name.+--            sortFlatMultiBalanceReportRowsByAccountCodeAndName = sortBy (comparing acodeandname)+--              where+--                acodeandname r = (acode', aname)+--                  where+--                    aname = first6 r+--                    macode = fromMaybe Nothing $ lookup aname $ jaccounts j+--                    acode' = fromMaybe maxBound macode+--+--            -- Sort the report rows, representing a tree of accounts, by account code and then account name at each level.+--            -- Convert a tree of account names, look up the account codes, sort and flatten the tree, reorder the rows.+--            sortTreeMultiBalanceReportRowsByAccountCodeAndName rows = sortedrows+--              where+--                anamesandrows = [(first6 r, r) | r <- rows]+--                anames = map fst anamesandrows+--                nametree = treeFromPaths $ map expandAccountName anames+--                accounttree = nameTreeToAccount "root" nametree+--                accounttreewithcodes = mapAccounts (accountSetCodeFrom j) accounttree+--                sortedaccounttree = sortAccountTreeByAccountCodeAndName accounttreewithcodes+--                sortedaccounts = drop 1 $ flattenAccounts sortedaccounttree+--                -- dropped the root account, also ignore any parent accounts not in rows+--                sortedrows = concatMap (\a -> maybe [] (:[]) $ lookup (aname a) anamesandrows) sortedaccounts+--++    -- TODO: grand total & average shows 0% when there are no actual amounts, inconsistent with other cells+    totalrow =+      ( ""+      , ""+      , 0+      , [ (Map.lookup p totActualByPeriod, Map.lookup p totBudgetByPeriod) | p <- periods ] :: [(Maybe Total, Maybe BudgetTotal)]+      , ( Just actualgrandtot, Just budgetgrandtot ) :: (Maybe Total, Maybe BudgetTotal)+      , ( Just actualgrandavg, Just budgetgrandavg ) :: (Maybe Total, Maybe BudgetTotal)+      )+      where+        totBudgetByPeriod = Map.fromList $ zip budgetperiods budgettots :: Map DateSpan BudgetTotal+        totActualByPeriod = Map.fromList $ zip actualperiods actualtots :: Map DateSpan Change++  in+    PeriodicReport+      ( periods+      , rows+      , totalrow+      )++-- | Figure out the overall period of a BudgetReport.+budgetReportSpan :: BudgetReport -> DateSpan+budgetReportSpan (PeriodicReport ([], _, _))    = DateSpan Nothing Nothing+budgetReportSpan (PeriodicReport (spans, _, _)) = DateSpan (spanStart $ head spans) (spanEnd $ last spans)++-- | Render a budget report as plain text suitable for console output.+budgetReportAsText :: ReportOpts -> BudgetReport -> String+budgetReportAsText ropts budgetr =+  printf "Budget performance in %s:\n\n" (showDateSpan $ budgetReportSpan budgetr)+  ++ +  tableAsText ropts showcell (budgetReportAsTable ropts budgetr)+  where+    -- XXX lay out actual, percentage and/or goal in the single table cell for now, should probably use separate cells+    showcell :: (Maybe Change, Maybe BudgetGoal) -> String+    showcell (mactual, mbudget) = actualstr ++ " " ++ budgetstr+      where+        actualwidth  = 7+        percentwidth = 4+        budgetwidth  = 5+        actual = fromMaybe 0 mactual+        actualstr = printf ("%"++show actualwidth++"s") (showamt actual)+        budgetstr = case mbudget of+          Nothing     -> replicate (percentwidth + 7 + budgetwidth) ' '+          Just budget ->+            case percentage actual budget of+              Just pct ->+                printf ("[%"++show percentwidth++"s%% of %"++show budgetwidth++"s]")+                       (show $ roundTo 0 pct) (showbudgetamt budget)+              Nothing ->+                printf ("["++replicate (percentwidth+5) ' '++"%"++show budgetwidth++"s]")+                       (showbudgetamt budget)++    -- | Calculate the percentage of actual change to budget goal to show, if any.+    -- Both amounts are converted to cost, if possible, before comparing.+    -- A percentage will not be shown if:+    -- - actual or goal are not the same, single, commodity+    -- - the goal is zero+    percentage :: Change -> BudgetGoal -> Maybe Percentage+    percentage actual budget =+      case (toCost actual, toCost budget) of+        (Mixed [a], Mixed [b]) | (acommodity a == acommodity b || isZeroAmount a) && not (isZeroAmount b) +            -> Just $ 100 * aquantity a / aquantity b+        _   -> Nothing+      where+        toCost = normaliseMixedAmount . costOfMixedAmount ++    showamt :: MixedAmount -> String+    showamt | color_ ropts  = cshowMixedAmountOneLineWithoutPrice+            | otherwise     = showMixedAmountOneLineWithoutPrice++    -- don't show the budget amount in color, it messes up alignment+    showbudgetamt = showMixedAmountOneLineWithoutPrice++-- | Build a 'Table' from a multi-column balance report.+budgetReportAsTable :: ReportOpts -> BudgetReport -> Table String String (Maybe MixedAmount, Maybe MixedAmount)+budgetReportAsTable +  ropts +  (PeriodicReport+    ( periods+    , rows+    , (_, _, _, coltots, grandtot, grandavg)+    )) =+    addtotalrow $ +    Table+      (T.Group NoLine $ map Header accts)+      (T.Group NoLine $ map Header colheadings)+      (map rowvals rows)+  where+    colheadings = map showDateSpanMonthAbbrev periods+                  ++ (if row_total_ ropts then ["  Total"] else [])+                  ++ (if average_   ropts then ["Average"] else [])+    accts = map renderacct rows+    renderacct (a,a',i,_,_,_)+      | tree_ ropts = replicate ((i-1)*2) ' ' ++ T.unpack a'+      | otherwise   = T.unpack $ maybeAccountNameDrop ropts a+    rowvals (_,_,_,as,rowtot,rowavg) = as+                                       ++ (if row_total_ ropts then [rowtot] else [])+                                       ++ (if average_   ropts then [rowavg] else [])+    addtotalrow | no_total_ ropts = id+                | otherwise       = (+----+ (row "" $+                                     coltots+                                     ++ (if row_total_ ropts && not (null coltots) then [grandtot] else [])+                                     ++ (if average_   ropts && not (null coltots) then [grandavg] else [])+                                     ))++-- XXX here for now+-- | Drop leading components of accounts names as specified by --drop, but only in --flat mode.+maybeAccountNameDrop :: ReportOpts -> AccountName -> AccountName+maybeAccountNameDrop opts a | tree_ opts = a+                            | otherwise  = accountNameDrop (drop_ opts) a++tests_Hledger_Reports_BudgetReport :: Test+tests_Hledger_Reports_BudgetReport = TestList [+  ]
Hledger/Reports/MultiBalanceReports.hs view
@@ -12,6 +12,8 @@   balanceReportFromMultiBalanceReport,   mbrNegate,   mbrNormaliseSign,+  multiBalanceReportSpan,+  tableAsText,    -- -- * Tests   tests_Hledger_Reports_MultiBalanceReport@@ -24,6 +26,8 @@ import Data.Time.Calendar import Safe import Test.HUnit+import Text.Tabular as T+import Text.Tabular.AsciiWide  import Hledger.Data import Hledger.Query@@ -259,6 +263,11 @@     mbrRowNegate (acct,shortacct,indent,amts,tot,avg) = (acct,shortacct,indent,map negate amts,-tot,-avg)     mbrTotalsRowNegate (amts,tot,avg) = (map negate amts,-tot,-avg) +-- | Figure out the overall date span of a multicolumn balance report.+multiBalanceReportSpan :: MultiBalanceReport -> DateSpan+multiBalanceReportSpan (MultiBalanceReport ([], _, _))       = DateSpan Nothing Nothing+multiBalanceReportSpan (MultiBalanceReport (colspans, _, _)) = DateSpan (spanStart $ head colspans) (spanEnd $ last colspans)+ -- | Generates a simple non-columnar BalanceReport, but using multiBalanceReport,  -- in order to support --historical. Does not support tree-mode boring parent eliding.  -- If the normalbalance_ option is set, it adjusts the sorting and sign of amounts @@ -321,6 +330,22 @@       ],       Mixed [usd0])   ]++-- common rendering helper, XXX here for now++tableAsText :: ReportOpts -> (a -> String) -> Table String String a -> String+tableAsText (ReportOpts{pretty_tables_ = pretty}) showcell =+  unlines+  . trimborder+  . lines+  . render pretty id id showcell+  . align+  where+    trimborder = drop 1 . init . map (drop 1 . init)+    align (Table l t d) = Table l' t d+      where+        acctswidth = maximum' $ map strWidth (headerContents l)+        l'         = padRightWide acctswidth <$> l  tests_Hledger_Reports_MultiBalanceReport :: Test tests_Hledger_Reports_MultiBalanceReport = TestList
Hledger/Reports/ReportOptions.hs view
@@ -115,7 +115,6 @@       --   normally positive for a more conventional display.        ,color_          :: Bool     ,forecast_       :: Bool-    ,auto_           :: Bool  } deriving (Show, Data, Typeable)  instance Default ReportOpts where def = defreportopts@@ -148,7 +147,6 @@     def     def     def-    def  rawOptsToReportOpts :: RawOpts -> IO ReportOpts rawOptsToReportOpts rawopts = checkReportOpts <$> do@@ -181,7 +179,6 @@     ,pretty_tables_ = boolopt "pretty-tables" rawopts'     ,color_       = color     ,forecast_    = boolopt "forecast" rawopts'-    ,auto_        = boolopt "auto" rawopts'     }  -- | Do extra validation of raw option values, raising an error if there's a problem.
+ Hledger/Reports/ReportTypes.hs view
@@ -0,0 +1,40 @@+{- |+New common report types, used by the BudgetReport for now, perhaps all reports later.+-}++module Hledger.Reports.ReportTypes+where++import Data.Decimal+import Hledger.Data++type Percentage = Decimal++type Change  = MixedAmount  -- ^ A change in balance during a certain period.+type Balance = MixedAmount  -- ^ An ending balance as of some date.+type Total   = MixedAmount  -- ^ The sum of 'Change's in a report or a report row. Does not make sense for 'Balance's.+type Average = MixedAmount  -- ^ The average of 'Change's or 'Balance's in a report or report row.++-- | A generic tabular report of some value, where each row corresponds to an account+-- and each column is a date period. The column periods are usually consecutive subperiods+-- formed by splitting the overall report period by some report interval (daily, weekly, etc.)+-- Depending on the value type, this can be a report of balance changes, ending balances,+-- budget performance, etc. Successor to MultiBalanceReport.+data PeriodicReport a =+  PeriodicReport+    ( [DateSpan]            -- The subperiods formed by splitting the overall report period by the report interval.+                            -- For ending-balance reports, only the end date is significant.+                            -- Usually displayed as report columns.+    , [PeriodicReportRow a] -- One row per account in the report.+    , PeriodicReportRow a   -- The grand totals row. The account name in this row is always empty.+    )+   deriving (Show)++type PeriodicReportRow a =+  ( AccountName  -- A full account name.+  , AccountName  -- Shortened form of the account name to display in tree mode. Usually the leaf name, possibly with parent accounts prefixed.+  , Int          -- Indent level for displaying this account name in tree mode. 0, 1, 2... +  , [a]          -- The data value for each subperiod.+  , a            -- The total of this row's values.+  , a            -- The average of this row's values.+  )
+ Text/Tabular/AsciiWide.hs view
@@ -0,0 +1,111 @@+-- | Text.Tabular.AsciiArt from tabular-0.2.2.7, modified to treat+-- wide characters as double width.++module Text.Tabular.AsciiWide where++import Data.List (intersperse, transpose)+import Text.Tabular+import Hledger.Utils.String++-- | for simplicity, we assume that each cell is rendered+--   on a single line+render :: Bool -- ^ pretty tables+       -> (rh -> String)+       -> (ch -> String)+       -> (a -> String)+       -> Table rh ch a+       -> String+render pretty fr fc f (Table rh ch cells) =+  unlines $ [ bar SingleLine   -- +--------------------------------------++            , renderColumns pretty sizes ch2+            , bar DoubleLine   -- +======================================++            ] +++            (renderRs $ fmap renderR $ zipHeader [] cells $ fmap fr rh) +++            [ bar SingleLine ] -- +--------------------------------------++ where+  bar = concat . renderHLine pretty sizes ch2+  -- ch2 and cell2 include the row and column labels+  ch2 = Group DoubleLine [Header "", fmap fc ch]+  cells2 = headerContents ch2+         : zipWith (\h cs -> h : map f cs) rhStrings cells+  --+  renderR (cs,h) = renderColumns pretty sizes $ Group DoubleLine+                    [ Header h+                    , fmap fst $ zipHeader "" (map f cs) ch]+  rhStrings = map fr $ headerContents rh+  -- maximum width for each column+  sizes   = map (maximum . map strWidth) . transpose $ cells2+  renderRs (Header s)   = [s]+  renderRs (Group p hs) = concat . intersperse sep . map renderRs $ hs+    where sep = renderHLine pretty sizes ch2 p++verticalBar :: Bool -> Char+verticalBar pretty = if pretty then '│' else '|'++leftBar :: Bool -> String+leftBar pretty = verticalBar pretty : " "++rightBar :: Bool -> String+rightBar pretty = " " ++ [verticalBar pretty]++midBar :: Bool -> String+midBar pretty = " " ++ verticalBar pretty : " "++doubleMidBar :: Bool -> String+doubleMidBar pretty = if pretty then " ║ " else " || "++horizontalBar :: Bool -> Char+horizontalBar pretty = if pretty then '─' else '-'++doubleHorizontalBar :: Bool -> Char+doubleHorizontalBar pretty = if pretty then '═' else '='++-- | We stop rendering on the shortest list!+renderColumns :: Bool -- ^ pretty+              -> [Int] -- ^ max width for each column+              -> Header String+              -> String+renderColumns pretty is h = leftBar pretty ++ coreLine ++ rightBar pretty+ where+  coreLine = concatMap helper $ flattenHeader $ zipHeader 0 is h+  helper = either hsep (uncurry padLeftWide)+  hsep :: Properties -> String+  hsep NoLine     = "  "+  hsep SingleLine = midBar pretty+  hsep DoubleLine = doubleMidBar pretty++renderHLine :: Bool -- ^ pretty+            -> [Int] -- ^ width specifications+            -> Header String+            -> Properties+            -> [String]+renderHLine _ _ _ NoLine = []+renderHLine pretty w h SingleLine = [renderHLine' pretty SingleLine w (horizontalBar pretty) h]+renderHLine pretty w h DoubleLine = [renderHLine' pretty DoubleLine w (doubleHorizontalBar pretty) h]++doubleCross :: Bool -> String+doubleCross pretty = if pretty then "╬" else "++"++doubleVerticalCross :: Bool -> String+doubleVerticalCross pretty = if pretty then "╫" else "++"++cross :: Bool -> Char+cross pretty = if pretty then '┼' else '+'++renderHLine' :: Bool -> Properties -> [Int] -> Char -> Header String -> String+renderHLine' pretty prop is sep h = [ cross pretty, sep ] ++ coreLine ++ [sep, cross pretty]+ where+  coreLine        = concatMap helper $ flattenHeader $ zipHeader 0 is h+  helper          = either vsep dashes+  dashes (i,_)    = replicate i sep+  vsep NoLine     = replicate 2 sep  -- match the double space sep in renderColumns +  vsep SingleLine = sep : cross pretty : [sep]+  vsep DoubleLine = sep : cross' ++ [sep]+  cross' = case prop of+     DoubleLine -> doubleCross pretty+     _ -> doubleVerticalCross pretty++-- padLeft :: Int -> String -> String+-- padLeft l s = padding ++ s+--  where padding = replicate (l - length s) ' '+
hledger-lib.cabal view
@@ -1,11 +1,11 @@--- This file has been generated from package.yaml by hpack version 0.20.0.+-- This file has been generated from package.yaml by hpack version 0.28.2. -- -- see: https://github.com/sol/hpack ----- hash: 151fb38a89818af88d66f068ef87e0af6f8497b1ef11ab825558b8147952c88d+-- hash: 1905b347a666e216347e595c5fcb0b340e5618a383a5493438200c6bcd5e6f98  name:           hledger-lib-version:        1.9+version:        1.9.1 synopsis:       Core data types, parsers and functionality for the hledger accounting tools description:    This is a reusable library containing hledger's core functionality.                 .@@ -26,7 +26,6 @@ tested-with:    GHC==7.10.3, GHC==8.0.2, GHC==8.2.1 build-type:     Simple cabal-version:  >= 1.10- extra-source-files:     CHANGES     hledger_csv.5@@ -48,44 +47,6 @@   location: https://github.com/simonmichael/hledger  library-  hs-source-dirs:-      ./.-  ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans-  build-depends:-      Decimal-    , HUnit-    , ansi-terminal >=0.6.2.3-    , array-    , base >=4.8 && <4.12-    , base-compat >=0.8.1-    , blaze-markup >=0.5.1-    , bytestring-    , cmdargs >=0.10-    , containers-    , csv-    , data-default >=0.5-    , deepseq-    , directory-    , extra-    , filepath-    , hashtables >=1.2-    , megaparsec >=5.0-    , mtl-    , mtl-compat-    , old-time-    , parsec >=3-    , pretty-show >=1.6.4-    , regex-tdfa-    , safe >=0.2-    , split >=0.1-    , text >=1.2-    , time >=1.5-    , transformers >=0.2-    , uglymemo-    , utf8-string >=0.3.5-  if (!impl(ghc >= 8.0))-    build-depends:-        semigroups ==0.18.*   exposed-modules:       Hledger       Hledger.Data@@ -114,8 +75,10 @@       Hledger.Read.TimeclockReader       Hledger.Reports       Hledger.Reports.ReportOptions+      Hledger.Reports.ReportTypes       Hledger.Reports.BalanceHistoryReport       Hledger.Reports.BalanceReport+      Hledger.Reports.BudgetReport       Hledger.Reports.EntriesReport       Hledger.Reports.MultiBalanceReports       Hledger.Reports.PostingsReport@@ -131,20 +94,14 @@       Hledger.Utils.Tree       Hledger.Utils.UTF8IOCompat       Text.Megaparsec.Compat+      Text.Tabular.AsciiWide   other-modules:       Paths_hledger_lib-  default-language: Haskell2010--test-suite doctests-  type: exitcode-stdio-1.0-  main-is: doctests.hs   hs-source-dirs:       ./.-      tests   ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans   build-depends:       Decimal-    , Glob >=0.7     , HUnit     , ansi-terminal >=0.6.2.3     , array@@ -158,7 +115,6 @@     , data-default >=0.5     , deepseq     , directory-    , doctest >=0.8     , extra     , filepath     , hashtables >=1.2@@ -171,6 +127,7 @@     , regex-tdfa     , safe >=0.2     , split >=0.1+    , tabular >=0.2     , text >=1.2     , time >=1.5     , transformers >=0.2@@ -179,8 +136,11 @@   if (!impl(ghc >= 8.0))     build-depends:         semigroups ==0.18.*-  if impl(ghc >= 8.4) && os(darwin)-    buildable: False+  default-language: Haskell2010++test-suite doctests+  type: exitcode-stdio-1.0+  main-is: doctests.hs   other-modules:       Hledger       Hledger.Data@@ -210,10 +170,12 @@       Hledger.Reports       Hledger.Reports.BalanceHistoryReport       Hledger.Reports.BalanceReport+      Hledger.Reports.BudgetReport       Hledger.Reports.EntriesReport       Hledger.Reports.MultiBalanceReports       Hledger.Reports.PostingsReport       Hledger.Reports.ReportOptions+      Hledger.Reports.ReportTypes       Hledger.Reports.TransactionsReports       Hledger.Utils       Hledger.Utils.Color@@ -226,18 +188,15 @@       Hledger.Utils.Tree       Hledger.Utils.UTF8IOCompat       Text.Megaparsec.Compat+      Text.Tabular.AsciiWide       Paths_hledger_lib-  default-language: Haskell2010--test-suite easytests-  type: exitcode-stdio-1.0-  main-is: easytests.hs   hs-source-dirs:       ./.       tests   ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans   build-depends:       Decimal+    , Glob >=0.7     , HUnit     , ansi-terminal >=0.6.2.3     , array@@ -251,11 +210,10 @@     , data-default >=0.5     , deepseq     , directory-    , easytest+    , doctest >=0.8     , extra     , filepath     , hashtables >=1.2-    , hledger-lib     , megaparsec >=5.0     , mtl     , mtl-compat@@ -265,6 +223,7 @@     , regex-tdfa     , safe >=0.2     , split >=0.1+    , tabular >=0.2     , text >=1.2     , time >=1.5     , transformers >=0.2@@ -273,6 +232,13 @@   if (!impl(ghc >= 8.0))     build-depends:         semigroups ==0.18.*+  if impl(ghc >= 8.4) && os(darwin)+    buildable: False+  default-language: Haskell2010++test-suite easytests+  type: exitcode-stdio-1.0+  main-is: easytests.hs   other-modules:       Hledger       Hledger.Data@@ -302,10 +268,12 @@       Hledger.Reports       Hledger.Reports.BalanceHistoryReport       Hledger.Reports.BalanceReport+      Hledger.Reports.BudgetReport       Hledger.Reports.EntriesReport       Hledger.Reports.MultiBalanceReports       Hledger.Reports.PostingsReport       Hledger.Reports.ReportOptions+      Hledger.Reports.ReportTypes       Hledger.Reports.TransactionsReports       Hledger.Utils       Hledger.Utils.Color@@ -318,12 +286,8 @@       Hledger.Utils.Tree       Hledger.Utils.UTF8IOCompat       Text.Megaparsec.Compat+      Text.Tabular.AsciiWide       Paths_hledger_lib-  default-language: Haskell2010--test-suite hunittests-  type: exitcode-stdio-1.0-  main-is: hunittests.hs   hs-source-dirs:       ./.       tests@@ -343,6 +307,7 @@     , data-default >=0.5     , deepseq     , directory+    , easytest     , extra     , filepath     , hashtables >=1.2@@ -356,8 +321,7 @@     , regex-tdfa     , safe >=0.2     , split >=0.1-    , test-framework-    , test-framework-hunit+    , tabular >=0.2     , text >=1.2     , time >=1.5     , transformers >=0.2@@ -366,6 +330,11 @@   if (!impl(ghc >= 8.0))     build-depends:         semigroups ==0.18.*+  default-language: Haskell2010++test-suite hunittests+  type: exitcode-stdio-1.0+  main-is: hunittests.hs   other-modules:       Hledger       Hledger.Data@@ -395,10 +364,12 @@       Hledger.Reports       Hledger.Reports.BalanceHistoryReport       Hledger.Reports.BalanceReport+      Hledger.Reports.BudgetReport       Hledger.Reports.EntriesReport       Hledger.Reports.MultiBalanceReports       Hledger.Reports.PostingsReport       Hledger.Reports.ReportOptions+      Hledger.Reports.ReportTypes       Hledger.Reports.TransactionsReports       Hledger.Utils       Hledger.Utils.Color@@ -411,5 +382,49 @@       Hledger.Utils.Tree       Hledger.Utils.UTF8IOCompat       Text.Megaparsec.Compat+      Text.Tabular.AsciiWide       Paths_hledger_lib+  hs-source-dirs:+      ./.+      tests+  ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans+  build-depends:+      Decimal+    , HUnit+    , ansi-terminal >=0.6.2.3+    , array+    , base >=4.8 && <4.12+    , base-compat >=0.8.1+    , blaze-markup >=0.5.1+    , bytestring+    , cmdargs >=0.10+    , containers+    , csv+    , data-default >=0.5+    , deepseq+    , directory+    , extra+    , filepath+    , hashtables >=1.2+    , hledger-lib+    , megaparsec >=5.0+    , mtl+    , mtl-compat+    , old-time+    , parsec >=3+    , pretty-show >=1.6.4+    , regex-tdfa+    , safe >=0.2+    , split >=0.1+    , tabular >=0.2+    , test-framework+    , test-framework-hunit+    , text >=1.2+    , time >=1.5+    , transformers >=0.2+    , uglymemo+    , utf8-string >=0.3.5+  if (!impl(ghc >= 8.0))+    build-depends:+        semigroups ==0.18.*   default-language: Haskell2010
hledger_csv.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_csv" "5" "March 2018" "hledger 1.9" "hledger User Manuals"+.TH "hledger_csv" "5" "April 2018" "hledger 1.9.1" "hledger User Manuals"   
hledger_csv.info view
@@ -3,8 +3,8 @@  File: hledger_csv.info,  Node: Top,  Next: CSV RULES,  Up: (dir) -hledger_csv(5) hledger 1.9-**************************+hledger_csv(5) hledger 1.9.1+****************************  hledger can read CSV (comma-separated value) files as if they were journal files, automatically converting each CSV record into a@@ -317,33 +317,33 @@  Tag Table: Node: Top72-Node: CSV RULES2161-Ref: #csv-rules2269-Node: skip2531-Ref: #skip2625-Node: date-format2797-Ref: #date-format2924-Node: field list3430-Ref: #field-list3567-Node: field assignment4272-Ref: #field-assignment4427-Node: conditional block4931-Ref: #conditional-block5085-Node: include5981-Ref: #include6111-Node: newest-first6342-Ref: #newest-first6456-Node: CSV TIPS6867-Ref: #csv-tips6961-Node: CSV ordering7079-Ref: #csv-ordering7197-Node: CSV accounts7378-Ref: #csv-accounts7516-Node: CSV amounts7770-Ref: #csv-amounts7916-Node: CSV balance assertions8691-Ref: #csv-balance-assertions8873-Node: Reading multiple CSV files9078-Ref: #reading-multiple-csv-files9248+Node: CSV RULES2165+Ref: #csv-rules2273+Node: skip2535+Ref: #skip2629+Node: date-format2801+Ref: #date-format2928+Node: field list3434+Ref: #field-list3571+Node: field assignment4276+Ref: #field-assignment4431+Node: conditional block4935+Ref: #conditional-block5089+Node: include5985+Ref: #include6115+Node: newest-first6346+Ref: #newest-first6460+Node: CSV TIPS6871+Ref: #csv-tips6965+Node: CSV ordering7083+Ref: #csv-ordering7201+Node: CSV accounts7382+Ref: #csv-accounts7520+Node: CSV amounts7774+Ref: #csv-amounts7920+Node: CSV balance assertions8695+Ref: #csv-balance-assertions8877+Node: Reading multiple CSV files9082+Ref: #reading-multiple-csv-files9252  End Tag Table
hledger_csv.txt view
@@ -249,4 +249,4 @@   -hledger 1.9                       March 2018                    hledger_csv(5)+hledger 1.9.1                     April 2018                    hledger_csv(5)
hledger_journal.5 view
@@ -1,6 +1,6 @@ .\"t -.TH "hledger_journal" "5" "March 2018" "hledger 1.9" "hledger User Manuals"+.TH "hledger_journal" "5" "April 2018" "hledger 1.9.1" "hledger User Manuals"   @@ -758,11 +758,6 @@ (Star comments cause org\-mode nodes to be ignored, allowing emacs users to fold and navigate their journals with org\-mode or orgstruct\-mode.) .PP-Also, anything between \f[C]comment\f[] and \f[C]end\ comment\f[]-directives is a (multi\-line) comment.-If there is no \f[C]end\ comment\f[], the comment extends to the end of-the file.-.PP You can attach comments to a transaction by writing them after the description and/or indented on the following lines (before the postings).@@ -795,6 +790,9 @@ ;\ a\ file\ comment\ (because\ not\ indented) \f[] .fi+.PP+You can also comment larger regions of a file using \f[C]comment\f[] and+\f[C]end\ comment\f[] directives. .SS Tags .PP Tags are a way to add extra labels or labelled data to postings and@@ -855,8 +853,174 @@ Tags are like Ledger's metadata feature, except hledger's tag values are simple strings. .SS Directives-.SS Account aliases+.SS Comment blocks .PP+A line containing just \f[C]comment\f[] starts a commented region of the+file, and a line containing just \f[C]end\ comment\f[] (or the end of+the current file) ends it.+See also comments.+.SS Including other files+.PP+You can pull in the content of additional files by writing an include+directive, like this:+.IP+.nf+\f[C]+include\ path/to/file.journal+\f[]+.fi+.PP+If the path does not begin with a slash, it is relative to the current+file.+Glob patterns (\f[C]*\f[]) are not currently supported.+.PP+The \f[C]include\f[] directive can only be used in journal files.+It can include journal, timeclock or timedot files, but not CSV files.+.SS Default year+.PP+You can set a default year to be used for subsequent dates which don't+specify a year.+This is a line beginning with \f[C]Y\f[] followed by the year.+Eg:+.IP+.nf+\f[C]+Y2009\ \ \ \ \ \ ;\ set\ default\ year\ to\ 2009++12/15\ \ \ \ \ \ ;\ equivalent\ to\ 2009/12/15+\ \ expenses\ \ 1+\ \ assets++Y2010\ \ \ \ \ \ ;\ change\ default\ year\ to\ 2010++2009/1/30\ \ ;\ specifies\ the\ year,\ not\ affected+\ \ expenses\ \ 1+\ \ assets++1/31\ \ \ \ \ \ \ ;\ equivalent\ to\ 2010/1/31+\ \ expenses\ \ 1+\ \ assets+\f[]+.fi+.SS Declaring commodities+.PP+The \f[C]commodity\f[] directive declares commodities which may be used+in the journal (though currently we do not enforce this).+It may be written on a single line, like this:+.IP+.nf+\f[C]+;\ commodity\ EXAMPLEAMOUNT++;\ display\ AAAA\ amounts\ with\ the\ symbol\ on\ the\ right,\ space\-separated,+;\ using\ period\ as\ decimal\ point,\ with\ four\ decimal\ places,\ and+;\ separating\ thousands\ with\ comma.+commodity\ 1,000.0000\ AAAA+\f[]+.fi+.PP+or on multiple lines, using the \[lq]format\[rq] subdirective.+In this case the commodity symbol appears twice and should be the same+in both places:+.IP+.nf+\f[C]+;\ commodity\ SYMBOL+;\ \ \ format\ EXAMPLEAMOUNT++;\ display\ indian\ rupees\ with\ currency\ name\ on\ the\ left,+;\ thousands,\ lakhs\ and\ crores\ comma\-separated,+;\ period\ as\ decimal\ point,\ and\ two\ decimal\ places.+commodity\ INR+\ \ format\ INR\ 9,99,99,999.00+\f[]+.fi+.PP+Commodity directives have a second purpose: they define the standard+display format for amounts in the commodity.+Normally the display format is inferred from journal entries, but this+can be unpredictable; declaring it with a commodity directive overrides+this and removes ambiguity.+Towards this end, amounts in commodity directives must always be written+with a decimal point (a period or comma, followed by 0 or more decimal+digits).+.SS Default commodity+.PP+The D directive sets a default commodity (and display format), to be+used for amounts without a commodity symbol (ie, plain numbers).+(Note this differs from Ledger's default commodity directive.) The+commodity and display format will be applied to all subsequent+commodity\-less amounts, or until the next D directive.+.IP+.nf+\f[C]+#\ commodity\-less\ amounts\ should\ be\ treated\ as\ dollars+#\ (and\ displayed\ with\ symbol\ on\ the\ left,\ thousands\ separators\ and\ two\ decimal\ places)+D\ $1,000.00++1/1+\ \ a\ \ \ \ \ 5\ \ \ \ ;\ <\-\ commodity\-less\ amount,\ becomes\ $1+\ \ b+\f[]+.fi+.PP+As with the \f[C]commodity\f[] directive, the amount must always be+written with a decimal point.+.SS Declaring accounts+.PP+The \f[C]account\f[] directive predeclares account names.+The simplest form is \f[C]account\ ACCTNAME\f[], eg:+.IP+.nf+\f[C]+account\ assets:bank:checking+\f[]+.fi+.PP+Currently this mainly helps with account name autocompletion in eg+hledger add, hledger\-iadd, hledger\-web, and ledger\-mode.+.PD 0+.P+.PD+In future it will also help detect misspelled accounts.+.PP+Account names can be followed by a numeric account code:+.IP+.nf+\f[C]+account\ assets\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1000+account\ assets:bank:checking\ \ \ \ 1110+account\ liabilities\ \ \ \ \ \ \ \ \ \ \ \ \ 2000+account\ revenues\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 4000+account\ expenses\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 6000+\f[]+.fi+.PP+This affects account display order in reports: accounts with codes are+listed before accounts without codes, in increasing code order.+(Otherwise, accounts are listed alphabetically.) Account codes should be+all numeric digits, unique, and separated from the account name by at+least two spaces (since account names may contain single spaces).+By convention, often the first digit indicates the type of account, as+in this numbering scheme and the example above.+In future, we might use this to recognize account types.+.PP+An account directive can also have indented subdirectives following it,+which are currently ignored.+Here is the full syntax:+.IP+.nf+\f[C]+;\ account\ ACCTNAME\ \ [OPTIONALCODE]+;\ \ \ [OPTIONALSUBDIRECTIVES]++account\ assets:bank:checking\ \ \ 1110+\ \ a\ comment+\ \ some\-tag:12345+\f[]+.fi+.SS Rewriting accounts+.PP You can define aliases which rewrite your account names (after reading the journal, before generating reports). hledger's account aliases can be useful for:@@ -871,7 +1035,7 @@ .IP \[bu] 2 customising reports .PP-See also Cookbook: rewrite account names.+See also Cookbook: Rewrite account names. .SS Basic aliases .PP To set an account alias, use the \f[C]alias\f[] directive in your@@ -946,7 +1110,7 @@ precedence over earlier ones; directives not yet seen are ignored) .IP "2." 3 alias options, in the order they appear on the command line-.SS end aliases+.SS \f[C]end\ aliases\f[] .PP You can clear (forget) all currently defined aliases with the \f[C]end\ aliases\f[] directive:@@ -956,60 +1120,7 @@ end\ aliases \f[] .fi-.SS account directive-.PP-The \f[C]account\f[] directive predeclares account names.-The simplest form is \f[C]account\ ACCTNAME\f[], eg:-.IP-.nf-\f[C]-account\ assets:bank:checking-\f[]-.fi-.PP-Currently this mainly helps with account name autocompletion in eg-hledger add, hledger\-iadd, hledger\-web, and ledger\-mode.-.PD 0-.P-.PD-In future it will also help detect misspelled accounts.-.PP-Account names can be followed by a numeric account code:-.IP-.nf-\f[C]-account\ assets\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 1000-account\ assets:bank:checking\ \ \ \ 1110-account\ liabilities\ \ \ \ \ \ \ \ \ \ \ \ \ 2000-account\ revenues\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 4000-account\ expenses\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 6000-\f[]-.fi-.PP-This affects account display order in reports: accounts with codes are-listed before accounts without codes, in increasing code order.-(Otherwise, accounts are listed alphabetically.) Account codes should be-all numeric digits, unique, and separated from the account name by at-least two spaces (since account names may contain single spaces).-By convention, often the first digit indicates the type of account, as-in this numbering scheme and the example above.-In future, we might use this to recognize account types.-.PP-An account directive can also have indented subdirectives following it,-which are currently ignored.-Here is the full syntax:-.IP-.nf-\f[C]-;\ account\ ACCTNAME\ \ [OPTIONALCODE]-;\ \ \ [OPTIONALSUBDIRECTIVES]--account\ assets:bank:checking\ \ \ 1110-\ \ a\ comment-\ \ some\-tag:12345-\f[]-.fi-.SS apply account directive+.SS Default parent account .PP You can specify a parent account which will be prepended to all accounts within a section of the journal.@@ -1054,116 +1165,13 @@ .PP Prior to hledger 1.0, legacy \f[C]account\f[] and \f[C]end\f[] spellings were also supported.-.SS Multi\-line comments-.PP-A line containing just \f[C]comment\f[] starts a multi\-line comment,-and a line containing just \f[C]end\ comment\f[] ends it.-See comments.-.SS commodity directive-.PP-The \f[C]commodity\f[] directive predefines commodities (currently this-is just informational), and also it may define the display format for-amounts in this commodity (overriding the automatically inferred-format).-.PP-It may be written on a single line, like this:-.IP-.nf-\f[C]-;\ commodity\ EXAMPLEAMOUNT--;\ display\ AAAA\ amounts\ with\ the\ symbol\ on\ the\ right,\ space\-separated,-;\ using\ period\ as\ decimal\ point,\ with\ four\ decimal\ places,\ and-;\ separating\ thousands\ with\ comma.-commodity\ 1,000.0000\ AAAA-\f[]-.fi-.PP-or on multiple lines, using the \[lq]format\[rq] subdirective.-In this case the commodity symbol appears twice and should be the same-in both places:-.IP-.nf-\f[C]-;\ commodity\ SYMBOL-;\ \ \ format\ EXAMPLEAMOUNT--;\ display\ indian\ rupees\ with\ currency\ name\ on\ the\ left,-;\ thousands,\ lakhs\ and\ crores\ comma\-separated,-;\ period\ as\ decimal\ point,\ and\ two\ decimal\ places.-commodity\ INR-\ \ format\ INR\ 9,99,99,999.00-\f[]-.fi-.SS Default commodity-.PP-The D directive sets a default commodity (and display format), to be-used for amounts without a commodity symbol (ie, plain numbers).-(Note this differs from Ledger's default commodity directive.) The-commodity and display format will be applied to all subsequent-commodity\-less amounts, or until the next D directive.-.IP-.nf-\f[C]-#\ commodity\-less\ amounts\ should\ be\ treated\ as\ dollars-#\ (and\ displayed\ with\ symbol\ on\ the\ left,\ thousands\ separators\ and\ two\ decimal\ places)-D\ $1,000.00--1/1-\ \ a\ \ \ \ \ 5\ \ \ \ ;\ <\-\ commodity\-less\ amount,\ becomes\ $1-\ \ b-\f[]-.fi-.SS Default year-.PP-You can set a default year to be used for subsequent dates which don't-specify a year.-This is a line beginning with \f[C]Y\f[] followed by the year.-Eg:-.IP-.nf-\f[C]-Y2009\ \ \ \ \ \ ;\ set\ default\ year\ to\ 2009--12/15\ \ \ \ \ \ ;\ equivalent\ to\ 2009/12/15-\ \ expenses\ \ 1-\ \ assets--Y2010\ \ \ \ \ \ ;\ change\ default\ year\ to\ 2010--2009/1/30\ \ ;\ specifies\ the\ year,\ not\ affected-\ \ expenses\ \ 1-\ \ assets--1/31\ \ \ \ \ \ \ ;\ equivalent\ to\ 2010/1/31-\ \ expenses\ \ 1-\ \ assets-\f[]-.fi-.SS Including other files-.PP-You can pull in the content of additional journal files by writing an-include directive, like this:-.IP-.nf-\f[C]-include\ path/to/file.journal-\f[]-.fi-.PP-If the path does not begin with a slash, it is relative to the current-file.-Glob patterns (\f[C]*\f[]) are not currently supported.-.PP-The \f[C]include\f[] directive can only be used in journal files.-It can include journal, timeclock or timedot files, but not CSV files.-.SH Periodic transactions+.SS Periodic transactions .PP-Periodic transactions are a kind of rule with a dual purpose: they can-specify recurring future transactions (with \f[C]\-\-forecast\f[]), or-budget goals (with \f[C]\-\-budget\f[]).-They look a bit like a transaction, except the first line is a tilde-(\f[C]~\f[]) followed by a period expression:+Periodic transaction rules (enabled by \f[C]\-\-forecast\f[] or+\f[C]\-\-budget\f[]) describe recurring transactions.+They look like a transaction where the first line is a tilde+(\f[C]~\f[]) followed by a period expression (mnemonic: \f[C]~\f[] is+like a recurring sine wave): .IP .nf \f[C]@@ -1173,25 +1181,34 @@ \f[] .fi .PP+Periodic transactions have a dual purpose:+.IP \[bu] 2 With \f[C]\-\-forecast\f[], each periodic transaction rule generates-recurring \[lq]forecast\[rq] transactions at the specified interval,-beginning the day after the latest recorded journal transaction (or-today, if there are no transactions) and ending 6 months from today (or-at the report end date, if specified).-.PP-With \f[C]balance\ \-\-budget\f[], each periodic transaction declares-recurring budget goals for the specified accounts.+future transactions, recurring at the specified interval, which can be+seen in reports.+Forecast transactions begin the day after the latest recorded journal+transaction (or today, if there are no transactions) and end 6 months+from today (or at the report end date, if specified).+.IP \[bu] 2+With \f[C]\-\-budget\f[] (supported by the balance command), each+periodic transaction rule declares recurring budget goals for the+specified accounts, which can be seen in budget reports. Eg the example above declares the goal of receiving $400 from \f[C]income:acme\ inc\f[] (and also, depositing $400 into \f[C]assets:bank:checking\f[]) every week. .PP-For more details, see: balance: Budgeting and Budgeting and Forecasting.-.SH Automated postings+(Actually, you can generate one\-off transactions too, by writing a+period expression with no report interval.) .PP-Automated postings are postings added automatically by rule to certain-transactions (with \f[C]\-\-auto\f[]).+For more details, see: balance: Budget report and Cookbook: Budgeting+and Forecasting.+.SS Automated postings+.PP+Automated postings (enabled by \f[C]\-\-auto\f[]) are postings added+automatically by rule to certain transactions. An automated posting rule looks like a transaction where the first line-is an equal sign (\f[C]=\f[]) followed by a query:+is an equal sign (\f[C]=\f[]) followed by a query (mnemonic: \f[C]=\f[]+tests for matching transactions, and also looks like posting lines): .IP .nf \f[C]@@ -1226,10 +1243,13 @@ $\ hledger\ print\ \-\-auto 2017/12/14 \ \ \ \ expenses:gifts\ \ \ \ \ \ \ \ \ \ \ \ \ $20-\ \ \ \ assets \ \ \ \ (budget:gifts)\ \ \ \ \ \ \ \ \ \ \ \ $\-20+\ \ \ \ assets \f[] .fi+.PP+Like postings recorded by hand, automated postings participate in+transaction balancing, missing amount inference and balance assertions. .SH EDITOR SUPPORT .PP Add\-on modes exist for various text editors, to make working with
hledger_journal.info view
@@ -4,8 +4,8 @@  File: hledger_journal.info,  Node: Top,  Next: FILE FORMAT,  Up: (dir) -hledger_journal(5) hledger 1.9-******************************+hledger_journal(5) hledger 1.9.1+********************************  hledger's usual data source is a plain text file containing journal entries in hledger journal format.  This file represents a standard@@ -57,12 +57,10 @@ * Menu:  * FILE FORMAT::-* Periodic transactions::-* Automated postings:: * EDITOR SUPPORT::  -File: hledger_journal.info,  Node: FILE FORMAT,  Next: Periodic transactions,  Prev: Top,  Up: Top+File: hledger_journal.info,  Node: FILE FORMAT,  Next: EDITOR SUPPORT,  Prev: Top,  Up: Top  1 FILE FORMAT *************@@ -83,6 +81,8 @@ * Comments:: * Tags:: * Directives::+* Periodic transactions::+* Automated postings::   File: hledger_journal.info,  Node: Transactions,  Next: Postings,  Up: FILE FORMAT@@ -713,10 +713,6 @@ org-mode nodes to be ignored, allowing emacs users to fold and navigate their journals with org-mode or orgstruct-mode.) -   Also, anything between 'comment' and 'end comment' directives is a-(multi-line) comment.  If there is no 'end comment', the comment extends-to the end of the file.-    You can attach comments to a transaction by writing them after the description and/or indented on the following lines (before the postings).  Similarly, you can attach comments to an individual posting@@ -744,6 +740,9 @@     ; another comment line for posting 2 ; a file comment (because not indented) +   You can also comment larger regions of a file using 'comment' and+'end comment' directives.+  File: hledger_journal.info,  Node: Tags,  Next: Directives,  Prev: Comments,  Up: FILE FORMAT @@ -788,28 +787,184 @@ are simple strings.  -File: hledger_journal.info,  Node: Directives,  Prev: Tags,  Up: FILE FORMAT+File: hledger_journal.info,  Node: Directives,  Next: Periodic transactions,  Prev: Tags,  Up: FILE FORMAT  1.14 Directives ===============  * Menu: -* Account aliases::-* account directive::-* apply account directive::-* Multi-line comments::-* commodity directive::-* Default commodity::-* Default year::+* Comment blocks:: * Including other files::+* Default year::+* Declaring commodities::+* Default commodity::+* Declaring accounts::+* Rewriting accounts::+* Default parent account::  -File: hledger_journal.info,  Node: Account aliases,  Next: account directive,  Up: Directives+File: hledger_journal.info,  Node: Comment blocks,  Next: Including other files,  Up: Directives -1.14.1 Account aliases-----------------------+1.14.1 Comment blocks+--------------------- +A line containing just 'comment' starts a commented region of the file,+and a line containing just 'end comment' (or the end of the current+file) ends it.  See also comments.+++File: hledger_journal.info,  Node: Including other files,  Next: Default year,  Prev: Comment blocks,  Up: Directives++1.14.2 Including other files+----------------------------++You can pull in the content of additional files by writing an include+directive, like this:++include path/to/file.journal++   If the path does not begin with a slash, it is relative to the+current file.  Glob patterns ('*') are not currently supported.++   The 'include' directive can only be used in journal files.  It can+include journal, timeclock or timedot files, but not CSV files.+++File: hledger_journal.info,  Node: Default year,  Next: Declaring commodities,  Prev: Including other files,  Up: Directives++1.14.3 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.+Eg:++Y2009      ; set default year to 2009++12/15      ; equivalent to 2009/12/15+  expenses  1+  assets++Y2010      ; change default year to 2010++2009/1/30  ; specifies the year, not affected+  expenses  1+  assets++1/31       ; equivalent to 2010/1/31+  expenses  1+  assets+++File: hledger_journal.info,  Node: Declaring commodities,  Next: Default commodity,  Prev: Default year,  Up: Directives++1.14.4 Declaring commodities+----------------------------++The 'commodity' directive declares commodities which may be used in the+journal (though currently we do not enforce this).  It may be written on+a single line, like this:++; commodity EXAMPLEAMOUNT++; display AAAA amounts with the symbol on the right, space-separated,+; using period as decimal point, with four decimal places, and+; 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+places:++; commodity SYMBOL+;   format EXAMPLEAMOUNT++; display indian rupees with currency name on the left,+; thousands, lakhs and crores comma-separated,+; period as decimal point, and two decimal places.+commodity INR+  format INR 9,99,99,999.00++   Commodity directives have a second purpose: they define the standard+display format for amounts in the commodity.  Normally the display+format is inferred from journal entries, but this can be unpredictable;+declaring it with a commodity directive overrides this and removes+ambiguity.  Towards this end, amounts in commodity directives must+always be written with a decimal point (a period or comma, followed by 0+or more decimal digits).+++File: hledger_journal.info,  Node: Default commodity,  Next: Declaring accounts,  Prev: Declaring commodities,  Up: Directives++1.14.5 Default commodity+------------------------++The D directive sets a default commodity (and display format), to be+used for amounts without a commodity symbol (ie, plain numbers).  (Note+this differs from Ledger's default commodity directive.)  The commodity+and display format will be applied to all subsequent commodity-less+amounts, or until the next D directive.++# commodity-less amounts should be treated as dollars+# (and displayed with symbol on the left, thousands separators and two decimal places)+D $1,000.00++1/1+  a     5    ; <- commodity-less amount, becomes $1+  b++   As with the 'commodity' directive, the amount must always be written+with a decimal point.+++File: hledger_journal.info,  Node: Declaring accounts,  Next: Rewriting accounts,  Prev: Default commodity,  Up: Directives++1.14.6 Declaring accounts+-------------------------++The 'account' directive predeclares account names.  The simplest form is+'account ACCTNAME', eg:++account assets:bank:checking++   Currently this mainly helps with account name autocompletion in eg+hledger add, hledger-iadd, hledger-web, and ledger-mode.+In future it will also help detect misspelled accounts.++   Account names can be followed by a numeric account code:++account assets                  1000+account assets:bank:checking    1110+account liabilities             2000+account revenues                4000+account expenses                6000++   This affects account display order in reports: accounts with codes+are listed before accounts without codes, in increasing code order.+(Otherwise, accounts are listed alphabetically.)  Account codes should+be all numeric digits, unique, and separated from the account name by at+least two spaces (since account names may contain single spaces).  By+convention, often the first digit indicates the type of account, as in+this numbering scheme and the example above.  In future, we might use+this to recognize account types.++   An account directive can also have indented subdirectives following+it, which are currently ignored.  Here is the full syntax:++; account ACCTNAME  [OPTIONALCODE]+;   [OPTIONALSUBDIRECTIVES]++account assets:bank:checking   1110+  a comment+  some-tag:12345+++File: hledger_journal.info,  Node: Rewriting accounts,  Next: Default parent account,  Prev: Declaring accounts,  Up: Directives++1.14.7 Rewriting accounts+-------------------------+ You can define aliases which rewrite your account names (after reading the journal, before generating reports).  hledger's account aliases can be useful for:@@ -821,7 +976,7 @@      or combining two accounts into one    * customising reports -   See also Cookbook: rewrite account names.+   See also Cookbook: Rewrite account names. * Menu:  * Basic aliases::@@ -830,9 +985,9 @@ * end aliases::  -File: hledger_journal.info,  Node: Basic aliases,  Next: Regex aliases,  Up: Account aliases+File: hledger_journal.info,  Node: Basic aliases,  Next: Regex aliases,  Up: Rewriting accounts -1.14.1.1 Basic aliases+1.14.7.1 Basic aliases ......................  To set an account alias, use the 'alias' directive in your journal file.@@ -853,9 +1008,9 @@ # rewrites "checking" to "assets:bank:wells fargo:checking", or "checking:a" to "assets:bank:wells fargo:checking:a"  -File: hledger_journal.info,  Node: Regex aliases,  Next: Multiple aliases,  Prev: Basic aliases,  Up: Account aliases+File: hledger_journal.info,  Node: Regex aliases,  Next: Multiple aliases,  Prev: Basic aliases,  Up: Rewriting accounts -1.14.1.2 Regex aliases+1.14.7.2 Regex aliases ......................  There is also a more powerful variant that uses a regular expression,@@ -878,9 +1033,9 @@ whitespace.  -File: hledger_journal.info,  Node: Multiple aliases,  Next: end aliases,  Prev: Regex aliases,  Up: Account aliases+File: hledger_journal.info,  Node: Multiple aliases,  Next: end aliases,  Prev: Regex aliases,  Up: Rewriting accounts -1.14.1.3 Multiple aliases+1.14.7.3 Multiple aliases .........................  You can define as many aliases as you like using directives or@@ -894,10 +1049,10 @@   2. alias options, in the order they appear on the command line  -File: hledger_journal.info,  Node: end aliases,  Prev: Multiple aliases,  Up: Account aliases+File: hledger_journal.info,  Node: end aliases,  Prev: Multiple aliases,  Up: Rewriting accounts -1.14.1.4 end aliases-....................+1.14.7.4 'end aliases'+......................  You can clear (forget) all currently defined aliases with the 'end aliases' directive:@@ -905,52 +1060,10 @@ end aliases  -File: hledger_journal.info,  Node: account directive,  Next: apply account directive,  Prev: Account aliases,  Up: Directives--1.14.2 account directive---------------------------The 'account' directive predeclares account names.  The simplest form is-'account ACCTNAME', eg:--account assets:bank:checking--   Currently this mainly helps with account name autocompletion in eg-hledger add, hledger-iadd, hledger-web, and ledger-mode.-In future it will also help detect misspelled accounts.--   Account names can be followed by a numeric account code:--account assets                  1000-account assets:bank:checking    1110-account liabilities             2000-account revenues                4000-account expenses                6000--   This affects account display order in reports: accounts with codes-are listed before accounts without codes, in increasing code order.-(Otherwise, accounts are listed alphabetically.)  Account codes should-be all numeric digits, unique, and separated from the account name by at-least two spaces (since account names may contain single spaces).  By-convention, often the first digit indicates the type of account, as in-this numbering scheme and the example above.  In future, we might use-this to recognize account types.--   An account directive can also have indented subdirectives following-it, which are currently ignored.  Here is the full syntax:--; account ACCTNAME  [OPTIONALCODE]-;   [OPTIONALSUBDIRECTIVES]--account assets:bank:checking   1110-  a comment-  some-tag:12345---File: hledger_journal.info,  Node: apply account directive,  Next: Multi-line comments,  Prev: account directive,  Up: Directives+File: hledger_journal.info,  Node: Default parent account,  Prev: Rewriting accounts,  Up: Directives -1.14.3 apply account directive-------------------------------+1.14.8 Default parent account+-----------------------------  You can specify a parent account which will be prepended to all accounts within a section of the journal.  Use the 'apply account' and 'end apply@@ -983,148 +1096,52 @@ supported.  -File: hledger_journal.info,  Node: Multi-line comments,  Next: commodity directive,  Prev: apply account directive,  Up: Directives--1.14.4 Multi-line comments-----------------------------A line containing just 'comment' starts a multi-line comment, and a line-containing just 'end comment' ends it.  See comments.---File: hledger_journal.info,  Node: commodity directive,  Next: Default commodity,  Prev: Multi-line comments,  Up: Directives--1.14.5 commodity directive-----------------------------The 'commodity' directive predefines commodities (currently this is just-informational), and also it may define the display format for amounts in-this commodity (overriding the automatically inferred format).--   It may be written on a single line, like this:--; commodity EXAMPLEAMOUNT--; display AAAA amounts with the symbol on the right, space-separated,-; using period as decimal point, with four decimal places, and-; 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-places:--; commodity SYMBOL-;   format EXAMPLEAMOUNT--; display indian rupees with currency name on the left,-; thousands, lakhs and crores comma-separated,-; period as decimal point, and two decimal places.-commodity INR-  format INR 9,99,99,999.00---File: hledger_journal.info,  Node: Default commodity,  Next: Default year,  Prev: commodity directive,  Up: Directives--1.14.6 Default commodity---------------------------The D directive sets a default commodity (and display format), to be-used for amounts without a commodity symbol (ie, plain numbers).  (Note-this differs from Ledger's default commodity directive.)  The commodity-and display format will be applied to all subsequent commodity-less-amounts, or until the next D directive.--# commodity-less amounts should be treated as dollars-# (and displayed with symbol on the left, thousands separators and two decimal places)-D $1,000.00--1/1-  a     5    ; <- commodity-less amount, becomes $1-  b---File: hledger_journal.info,  Node: Default year,  Next: Including other files,  Prev: Default commodity,  Up: Directives--1.14.7 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.-Eg:--Y2009      ; set default year to 2009--12/15      ; equivalent to 2009/12/15-  expenses  1-  assets--Y2010      ; change default year to 2010--2009/1/30  ; specifies the year, not affected-  expenses  1-  assets--1/31       ; equivalent to 2010/1/31-  expenses  1-  assets---File: hledger_journal.info,  Node: Including other files,  Prev: Default year,  Up: Directives--1.14.8 Including other files-------------------------------You can pull in the content of additional journal files by writing an-include directive, like this:--include path/to/file.journal--   If the path does not begin with a slash, it is relative to the-current file.  Glob patterns ('*') are not currently supported.--   The 'include' directive can only be used in journal files.  It can-include journal, timeclock or timedot files, but not CSV files.---File: hledger_journal.info,  Node: Periodic transactions,  Next: Automated postings,  Prev: FILE FORMAT,  Up: Top+File: hledger_journal.info,  Node: Periodic transactions,  Next: Automated postings,  Prev: Directives,  Up: FILE FORMAT -2 Periodic transactions-***********************+1.15 Periodic transactions+========================== -Periodic transactions are a kind of rule with a dual purpose: they can-specify recurring future transactions (with '--forecast'), or budget-goals (with '--budget').  They look a bit like a transaction, except the-first line is a tilde ('~') followed by a period expression:+Periodic transaction rules (enabled by '--forecast' or '--budget')+describe recurring transactions.  They look like a transaction where the+first line is a tilde ('~') followed by a period expression (mnemonic:+'~' is like a recurring sine wave):  ~ weekly   assets:bank:checking   $400 ; paycheck   income:acme inc -   With '--forecast', each periodic transaction rule generates recurring-"forecast" transactions at the specified interval, beginning the day-after the latest recorded journal transaction (or today, if there are no-transactions) and ending 6 months from today (or at the report end date,-if specified).+   Periodic transactions have a dual purpose: -   With 'balance --budget', each periodic transaction declares recurring-budget goals for the specified accounts.  Eg the example above declares-the goal of receiving $400 from 'income:acme inc' (and also, depositing-$400 into 'assets:bank:checking') every week.+   * With '--forecast', each periodic transaction rule generates future+     transactions, recurring at the specified interval, which can be+     seen in reports.  Forecast transactions begin the day after the+     latest recorded journal transaction (or today, if there are no+     transactions) and end 6 months from today (or at the report end+     date, if specified). -   For more details, see: balance: Budgeting and Budgeting and-Forecasting.+   * With '--budget' (supported by the balance command), each periodic+     transaction rule declares recurring budget goals for the specified+     accounts, which can be seen in budget reports.  Eg the example+     above declares the goal of receiving $400 from 'income:acme inc'+     (and also, depositing $400 into 'assets:bank:checking') every week. +   (Actually, you can generate one-off transactions too, by writing a+period expression with no report interval.)++   For more details, see: balance: Budget report and Cookbook: Budgeting+and Forecasting.+ -File: hledger_journal.info,  Node: Automated postings,  Next: EDITOR SUPPORT,  Prev: Periodic transactions,  Up: Top+File: hledger_journal.info,  Node: Automated postings,  Prev: Periodic transactions,  Up: FILE FORMAT -3 Automated postings-********************+1.16 Automated postings+======================= -Automated postings are postings added automatically by rule to certain-transactions (with '--auto').  An automated posting rule looks like a-transaction where the first line is an equal sign ('=') followed by a-query:+Automated postings (enabled by '--auto') are postings added+automatically by rule to certain transactions.  An automated posting+rule looks like a transaction where the first line is an equal sign+('=') followed by a query (mnemonic: '=' tests for matching+transactions, and also looks like posting lines):  = expenses:gifts     budget:gifts  *-1@@ -1149,13 +1166,16 @@ $ hledger print --auto 2017/12/14     expenses:gifts             $20-    assets     (budget:gifts)            $-20+    assets +   Like postings recorded by hand, automated postings participate in+transaction balancing, missing amount inference and balance assertions.+ -File: hledger_journal.info,  Node: EDITOR SUPPORT,  Prev: Automated postings,  Up: Top+File: hledger_journal.info,  Node: EDITOR SUPPORT,  Prev: FILE FORMAT,  Up: Top -4 EDITOR SUPPORT+2 EDITOR SUPPORT ****************  Add-on modes exist for various text editors, to make working with@@ -1182,89 +1202,89 @@  Tag Table: Node: Top76-Node: FILE FORMAT2419-Ref: #file-format2550-Node: Transactions2773-Ref: #transactions2894-Node: Postings3578-Ref: #postings3705-Node: Dates4700-Ref: #dates4815-Node: Simple dates4880-Ref: #simple-dates5006-Node: Secondary dates5372-Ref: #secondary-dates5526-Node: Posting dates7089-Ref: #posting-dates7218-Node: Status8592-Ref: #status8712-Node: Description10420-Ref: #description10558-Node: Payee and note10877-Ref: #payee-and-note10991-Node: Account names11233-Ref: #account-names11376-Node: Amounts11863-Ref: #amounts11999-Node: Virtual Postings15014-Ref: #virtual-postings15173-Node: Balance Assertions16393-Ref: #balance-assertions16568-Node: Assertions and ordering17464-Ref: #assertions-and-ordering17650-Node: Assertions and included files18350-Ref: #assertions-and-included-files18591-Node: Assertions and multiple -f options18924-Ref: #assertions-and-multiple--f-options19178-Node: Assertions and commodities19310-Ref: #assertions-and-commodities19545-Node: Assertions and subaccounts20241-Ref: #assertions-and-subaccounts20473-Node: Assertions and virtual postings20994-Ref: #assertions-and-virtual-postings21201-Node: Balance Assignments21343-Ref: #balance-assignments21512-Node: Prices22632-Ref: #prices22765-Node: Transaction prices22816-Ref: #transaction-prices22961-Node: Market prices25117-Ref: #market-prices25252-Node: Comments26212-Ref: #comments26334-Node: Tags27576-Ref: #tags27694-Node: Directives29096-Ref: #directives29209-Node: Account aliases29402-Ref: #account-aliases29546-Node: Basic aliases30150-Ref: #basic-aliases30293-Node: Regex aliases30983-Ref: #regex-aliases31151-Node: Multiple aliases31869-Ref: #multiple-aliases32041-Node: end aliases32539-Ref: #end-aliases32679-Node: account directive32780-Ref: #account-directive32960-Node: apply account directive34307-Ref: #apply-account-directive34503-Node: Multi-line comments35162-Ref: #multi-line-comments35352-Node: commodity directive35480-Ref: #commodity-directive35664-Node: Default commodity36536-Ref: #default-commodity36709-Node: Default year37246-Ref: #default-year37411-Node: Including other files37834-Ref: #including-other-files37991-Node: Periodic transactions38388-Ref: #periodic-transactions38554-Node: Automated postings39543-Ref: #automated-postings39706-Node: EDITOR SUPPORT40608-Ref: #editor-support40733+Node: FILE FORMAT2374+Ref: #file-format2498+Node: Transactions2770+Ref: #transactions2891+Node: Postings3575+Ref: #postings3702+Node: Dates4697+Ref: #dates4812+Node: Simple dates4877+Ref: #simple-dates5003+Node: Secondary dates5369+Ref: #secondary-dates5523+Node: Posting dates7086+Ref: #posting-dates7215+Node: Status8589+Ref: #status8709+Node: Description10417+Ref: #description10555+Node: Payee and note10874+Ref: #payee-and-note10988+Node: Account names11230+Ref: #account-names11373+Node: Amounts11860+Ref: #amounts11996+Node: Virtual Postings15011+Ref: #virtual-postings15170+Node: Balance Assertions16390+Ref: #balance-assertions16565+Node: Assertions and ordering17461+Ref: #assertions-and-ordering17647+Node: Assertions and included files18347+Ref: #assertions-and-included-files18588+Node: Assertions and multiple -f options18921+Ref: #assertions-and-multiple--f-options19175+Node: Assertions and commodities19307+Ref: #assertions-and-commodities19542+Node: Assertions and subaccounts20238+Ref: #assertions-and-subaccounts20470+Node: Assertions and virtual postings20991+Ref: #assertions-and-virtual-postings21198+Node: Balance Assignments21340+Ref: #balance-assignments21509+Node: Prices22629+Ref: #prices22762+Node: Transaction prices22813+Ref: #transaction-prices22958+Node: Market prices25114+Ref: #market-prices25249+Node: Comments26209+Ref: #comments26331+Node: Tags27501+Ref: #tags27619+Node: Directives29021+Ref: #directives29164+Node: Comment blocks29357+Ref: #comment-blocks29502+Node: Including other files29678+Ref: #including-other-files29858+Node: Default year30247+Ref: #default-year30416+Node: Declaring commodities30839+Ref: #declaring-commodities31022+Node: Default commodity32249+Ref: #default-commodity32430+Node: Declaring accounts33062+Ref: #declaring-accounts33242+Node: Rewriting accounts34589+Ref: #rewriting-accounts34774+Node: Basic aliases35378+Ref: #basic-aliases35524+Node: Regex aliases36214+Ref: #regex-aliases36385+Node: Multiple aliases37103+Ref: #multiple-aliases37278+Node: end aliases37776+Ref: #end-aliases37923+Node: Default parent account38024+Ref: #default-parent-account38190+Node: Periodic transactions38849+Ref: #periodic-transactions39028+Node: Automated postings40327+Ref: #automated-postings40481+Node: EDITOR SUPPORT41614+Ref: #editor-support41732  End Tag Table
hledger_journal.txt view
@@ -553,10 +553,6 @@        nodes to be ignored, allowing emacs users to fold  and  navigate  their        journals with org-mode or orgstruct-mode.) -       Also,   anything  between  comment  and  end comment  directives  is  a-       (multi-line) comment.  If there is no end comment, the comment  extends-       to the end of the file.-        You  can  attach  comments  to  a transaction by writing them after the        description and/or indented on the following lines  (before  the  post-        ings).   Similarly, you can attach comments to an individual posting by@@ -584,21 +580,24 @@                   ; another comment line for posting 2               ; a file comment (because not indented) +       You  can  also  comment  larger  regions  of  a  file using comment and+       end comment directives.+    Tags-       Tags  are  a  way  to add extra labels or labelled data to postings and+       Tags are a way to add extra labels or labelled  data  to  postings  and        transactions, which you can then search or pivot on. -       A simple tag is a word (which may contain hyphens) followed by  a  full+       A  simple  tag is a word (which may contain hyphens) followed by a full        colon, written inside a transaction or posting comment line:                2017/1/16 bought groceries    ; sometag: -       Tags  can  have  a  value, which is the text after the colon, up to the+       Tags can have a value, which is the text after the  colon,  up  to  the        next comma or end of line, with leading/trailing whitespace removed:                    expenses:food    $10   ; a-posting-tag: the tag value -       Note this means hledger's tag values can not  contain  commas  or  new-+       Note  this  means  hledger's  tag values can not contain commas or new-        lines.  Ending at commas means you can write multiple short tags on one        line, comma separated: @@ -612,21 +611,147 @@         o "tag2" is another tag, whose value is "some value ..." -       Tags in a transaction comment affect the transaction  and  all  of  its-       postings,  while  tags  in  a posting comment affect only that posting.-       For example,  the  following  transaction  has  three  tags  (A,  TAG2,+       Tags  in  a  transaction  comment affect the transaction and all of its+       postings, while tags in a posting comment  affect  only  that  posting.+       For  example,  the  following  transaction  has  three  tags  (A, TAG2,        third-tag) and the posting has four (those plus posting-tag):                1/1 a transaction  ; A:, TAG2:                   ; third-tag: a third transaction tag, <- with a value                   (a)  $1  ; posting-tag: -       Tags  are  like  Ledger's metadata feature, except hledger's tag values+       Tags are like Ledger's metadata feature, except  hledger's  tag  values        are simple strings.     Directives-   Account aliases-       You can define aliases which rewrite your account names (after  reading+   Comment blocks+       A  line  containing just comment starts a commented region of the file,+       and a line containing just end comment (or the end of the current file)+       ends it.  See also comments.++   Including other files+       You  can  pull in the content of additional files by writing an include+       directive, like this:++              include path/to/file.journal++       If the path does not begin with a slash, it is relative to the  current+       file.  Glob patterns (*) are not currently supported.++       The  include  directive  can  only  be  used  in journal files.  It can+       include journal, timeclock or timedot files, but not CSV files.++   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.+       Eg:++              Y2009      ; set default year to 2009++              12/15      ; equivalent to 2009/12/15+                expenses  1+                assets++              Y2010      ; change default year to 2010++              2009/1/30  ; specifies the year, not affected+                expenses  1+                assets++              1/31       ; equivalent to 2010/1/31+                expenses  1+                assets++   Declaring commodities+       The commodity directive declares commodities which may be used  in  the+       journal  (though  currently we do not enforce this).  It may be written+       on a single line, like this:++              ; commodity EXAMPLEAMOUNT++              ; display AAAA amounts with the symbol on the right, space-separated,+              ; using period as decimal point, with four decimal places, and+              ; 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+       places:++              ; commodity SYMBOL+              ;   format EXAMPLEAMOUNT++              ; display indian rupees with currency name on the left,+              ; thousands, lakhs and crores comma-separated,+              ; period as decimal point, and two decimal places.+              commodity INR+                format INR 9,99,99,999.00++       Commodity directives have a second purpose: they  define  the  standard+       display format for amounts in the commodity.  Normally the display for-+       mat is inferred from journal entries, but this  can  be  unpredictable;+       declaring  it  with  a  commodity  directive overrides this and removes+       ambiguity.  Towards this end,  amounts  in  commodity  directives  must+       always  be written with a decimal point (a period or comma, followed by+       0 or more decimal digits).++   Default commodity+       The D directive sets a default commodity (and display  format),  to  be+       used for amounts without a commodity symbol (ie, plain numbers).  (Note+       this differs from Ledger's default commodity directive.) The  commodity+       and  display  format  will  be applied to all subsequent commodity-less+       amounts, or until the next D directive.++              # commodity-less amounts should be treated as dollars+              # (and displayed with symbol on the left, thousands separators and two decimal places)+              D $1,000.00++              1/1+                a     5    ; <- commodity-less amount, becomes $1+                b++       As with the commodity directive, the amount must always be written with+       a decimal point.++   Declaring accounts+       The  account directive predeclares account names.  The simplest form is+       account ACCTNAME, eg:++              account assets:bank:checking++       Currently this mainly helps with  account  name  autocompletion  in  eg+       hledger add, hledger-iadd, hledger-web, and ledger-mode.+       In future it will also help detect misspelled accounts.++       Account names can be followed by a numeric account code:++              account assets                  1000+              account assets:bank:checking    1110+              account liabilities             2000+              account revenues                4000+              account expenses                6000++       This  affects account display order in reports: accounts with codes are+       listed before accounts without codes, in increasing code order.   (Oth-+       erwise,  accounts  are  listed alphabetically.) Account codes should be+       all numeric digits, unique, and separated from the account name  by  at+       least  two  spaces (since account names may contain single spaces).  By+       convention, often the first digit indicates the type of account, as  in+       this  numbering  scheme and the example above.  In future, we might use+       this to recognize account types.++       An account directive can also have indented subdirectives following it,+       which are currently ignored.  Here is the full syntax:++              ; account ACCTNAME  [OPTIONALCODE]+              ;   [OPTIONALSUBDIRECTIVES]++              account assets:bank:checking   1110+                a comment+                some-tag:12345++   Rewriting accounts+       You  can define aliases which rewrite your account names (after reading        the journal, before generating reports).  hledger's account aliases can        be useful for: @@ -640,11 +765,11 @@         o customising reports -       See also Cookbook: rewrite account names.+       See also Cookbook: 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@@ -652,91 +777,54 @@        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 full account names.  hledger will  replace  any  occur--       rence  of  the old account name with the new one.  Subaccounts are also+       OLD  and  NEW  are full account names.  hledger will replace any occur-+       rence of the old account name with the new one.  Subaccounts  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.     Multiple aliases-       You can define as many aliases as you like  using  directives  or  com--       mand-line  options.  Aliases are recursive - each alias sees the result-       of applying previous ones.   (This  is  different  from  Ledger,  where+       You  can  define  as  many aliases as you like using directives or com-+       mand-line options.  Aliases are recursive - each alias sees the  result+       of  applying  previous  ones.   (This  is  different from Ledger, where        aliases are non-recursive by default).  Aliases are applied in the fol-        lowing order: -       1. alias directives, most recently seen first (recent  directives  take+       1. alias  directives,  most recently seen first (recent directives take           precedence over earlier ones; directives not yet seen are ignored)         2. alias options, in the order they appear on the command line     end aliases-       You   can  clear  (forget)  all  currently  defined  aliases  with  the+       You  can  clear  (forget)  all  currently  defined  aliases  with   the        end aliases directive:                end aliases -   account directive-       The account directive predeclares account names.  The simplest form  is-       account ACCTNAME, eg:--              account assets:bank:checking--       Currently  this  mainly  helps  with  account name autocompletion in eg-       hledger add, hledger-iadd, hledger-web, and ledger-mode.-       In future it will also help detect misspelled accounts.--       Account names can be followed by a numeric account code:--              account assets                  1000-              account assets:bank:checking    1110-              account liabilities             2000-              account revenues                4000-              account expenses                6000--       This affects account display order in reports: accounts with codes  are-       listed  before accounts without codes, in increasing code order.  (Oth--       erwise, accounts are listed alphabetically.) Account  codes  should  be-       all  numeric  digits, unique, and separated from the account name by at-       least two spaces (since account names may contain single  spaces).   By-       convention,  often the first digit indicates the type of account, as in-       this numbering scheme and the example above.  In future, we  might  use-       this to recognize account types.--       An account directive can also have indented subdirectives following it,-       which are currently ignored.  Here is the full syntax:--              ; account ACCTNAME  [OPTIONALCODE]-              ;   [OPTIONALSUBDIRECTIVES]--              account assets:bank:checking   1110-                a comment-                some-tag:12345--   apply account directive-       You can specify a  parent  account  which  will  be  prepended  to  all-       accounts  within  a  section of the journal.  Use the apply account and+   Default parent account+       You  can  specify  a  parent  account  which  will  be prepended to all+       accounts within a section of the journal.  Use  the  apply account  and        end apply account directives like so:                apply account home@@ -753,7 +841,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@@ -762,129 +850,58 @@               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. -   Multi-line comments-       A line containing just comment starts a multi-line comment, and a  line-       containing just end comment ends it.  See comments.--   commodity directive-       The  commodity directive predefines commodities (currently this is just-       informational), and also it may define the display format  for  amounts-       in this commodity (overriding the automatically inferred format).--       It may be written on a single line, like this:--              ; commodity EXAMPLEAMOUNT--              ; display AAAA amounts with the symbol on the right, space-separated,-              ; using period as decimal point, with four decimal places, and-              ; 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-       places:--              ; commodity SYMBOL-              ;   format EXAMPLEAMOUNT--              ; display indian rupees with currency name on the left,-              ; thousands, lakhs and crores comma-separated,-              ; period as decimal point, and two decimal places.-              commodity INR-                format INR 9,99,99,999.00--   Default commodity-       The  D  directive  sets a default commodity (and display format), to be-       used for amounts without a commodity symbol (ie, plain numbers).  (Note-       this  differs from Ledger's default commodity directive.) The commodity-       and display format will be applied  to  all  subsequent  commodity-less-       amounts, or until the next D directive.--              # commodity-less amounts should be treated as dollars-              # (and displayed with symbol on the left, thousands separators and two decimal places)-              D $1,000.00--              1/1-                a     5    ; <- commodity-less amount, becomes $1-                b--   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.-       Eg:--              Y2009      ; set default year to 2009--              12/15      ; equivalent to 2009/12/15-                expenses  1-                assets--              Y2010      ; change default year to 2010--              2009/1/30  ; specifies the year, not affected-                expenses  1-                assets--              1/31       ; equivalent to 2010/1/31-                expenses  1-                assets--   Including other files-       You  can  pull in the content of additional journal files by writing an-       include directive, like this:--              include path/to/file.journal--       If the path does not begin with a slash, it is relative to the  current-       file.  Glob patterns (*) are not currently supported.--       The  include  directive  can  only  be  used  in journal files.  It can-       include journal, timeclock or timedot files, but not CSV files.--Periodic transactions-       Periodic transactions are a kind of rule with a dual purpose: they  can-       specify  recurring  future  transactions  (with  --forecast), or budget-       goals (with --budget).  They look a bit like a transaction, except  the-       first line is a tilde (~) followed by a period expression:+   Periodic transactions+       Periodic transaction rules (enabled by --forecast or --budget) describe+       recurring transactions.  They look like a transaction where  the  first+       line  is  a  tilde  (~) followed by a period expression (mnemonic: ~ is+       like a recurring sine wave):                ~ weekly                 assets:bank:checking   $400 ; paycheck                 income:acme inc -       With  --forecast,  each  periodic  transaction rule generates recurring-       "forecast" transactions at the specified interval,  beginning  the  day-       after  the  latest recorded journal transaction (or today, if there are-       no transactions) and ending 6 months from today (or at the  report  end-       date, if specified).+       Periodic transactions have a dual purpose: -       With  balance --budget,  each  periodic  transaction declares recurring-       budget goals for the specified accounts.  Eg the example above declares-       the  goal  of receiving $400 from income:acme inc (and also, depositing-       $400 into assets:bank:checking) every week.+       o With --forecast, each  periodic  transaction  rule  generates  future+         transactions,  recurring at the specified interval, which can be seen+         in reports.  Forecast transactions begin the  day  after  the  latest+         recorded journal transaction (or today, if there are no transactions)+         and end 6 months from today (or at the report  end  date,  if  speci-+         fied). -       For more details, see: balance: Budgeting and Budgeting  and  Forecast--       ing.+       o With  --budget  (supported  by  the  balance  command), each periodic+         transaction rule declares recurring budget goals  for  the  specified+         accounts,  which can be seen in budget reports.  Eg the example above+         declares the goal of receiving $400 from income:acme inc  (and  also,+         depositing $400 into assets:bank:checking) every week. -Automated postings-       Automated  postings are postings added automatically by rule to certain-       transactions (with --auto).  An automated posting  rule  looks  like  a-       transaction  where  the  first  line is an equal sign (=) followed by a-       query:+       (Actually,  you  can  generate  one-off  transactions too, by writing a+       period expression with no report interval.) +       For more details, see: balance: Budget report and  Cookbook:  Budgeting+       and Forecasting.++   Automated postings+       Automated postings (enabled by --auto) are postings added automatically+       by rule to certain transactions.  An automated posting rule looks  like+       a  transaction  where the first line is an equal sign (=) followed by a+       query (mnemonic: = tests for matching transactions, and also looks like+       posting lines):+               = expenses:gifts                   budget:gifts  *-1                   assets:budget  *1 -       The posting amounts can be of the form *N, which means "the  amount  of-       the  matched  transaction's  first posting, multiplied by N".  They can+       The  posting  amounts can be of the form *N, which means "the amount of+       the matched transaction's first posting, multiplied by  N".   They  can        also be ordinary fixed amounts.  Fixed amounts with no commodity symbol-       will  be  given  the  same commodity as the matched transaction's first+       will be given the same commodity as  the  matched  transaction's  first        posting. -       This example adds a corresponding (unbalanced) budget posting to  every+       This  example adds a corresponding (unbalanced) budget posting to every        transaction involving the expenses:gifts account:                = expenses:gifts@@ -897,16 +914,19 @@               $ hledger print --auto               2017/12/14                   expenses:gifts             $20-                  assets                   (budget:gifts)            $-20+                  assets +       Like postings recorded  by  hand,  automated  postings  participate  in+       transaction balancing, missing amount inference and balance assertions.+ EDITOR SUPPORT        Add-on modes exist for various text editors, to make working with jour--       nal files easier.  They add colour, navigation aids  and  helpful  com--       mands.   For  hledger  users  who  edit  the journal file directly (the+       nal  files  easier.   They add colour, navigation aids and helpful com-+       mands.  For hledger users who  edit  the  journal  file  directly  (the        majority), using one of these modes is quite recommended. -       These were written with Ledger in mind,  but  also  work  with  hledger+       These  were  written  with  Ledger  in mind, but also work with hledger        files:  @@ -925,7 +945,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)  @@ -939,7 +959,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) @@ -947,4 +967,4 @@   -hledger 1.9                       March 2018                hledger_journal(5)+hledger 1.9.1                     April 2018                hledger_journal(5)
hledger_timeclock.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_timeclock" "5" "March 2018" "hledger 1.9" "hledger User Manuals"+.TH "hledger_timeclock" "5" "April 2018" "hledger 1.9.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.9-********************************+hledger_timeclock(5) hledger 1.9.1+**********************************  hledger can read timeclock files.  As with Ledger, these are (a subset of) timeclock.el's format, containing clock-in and clock-out entries as
hledger_timeclock.txt view
@@ -77,4 +77,4 @@   -hledger 1.9                       March 2018              hledger_timeclock(5)+hledger 1.9.1                     April 2018              hledger_timeclock(5)
hledger_timedot.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_timedot" "5" "March 2018" "hledger 1.9" "hledger User Manuals"+.TH "hledger_timedot" "5" "April 2018" "hledger 1.9.1" "hledger User Manuals"   
hledger_timedot.info view
@@ -4,8 +4,8 @@  File: hledger_timedot.info,  Node: Top,  Next: FILE FORMAT,  Up: (dir) -hledger_timedot(5) hledger 1.9-******************************+hledger_timedot(5) hledger 1.9.1+********************************  Timedot is a plain text format for logging dated, categorised quantities (of time, usually), supported by hledger.  It is convenient for@@ -110,7 +110,7 @@  Tag Table: Node: Top76-Node: FILE FORMAT805-Ref: #file-format906+Node: FILE FORMAT809+Ref: #file-format910  End Tag Table
hledger_timedot.txt view
@@ -124,4 +124,4 @@   -hledger 1.9                       March 2018                hledger_timedot(5)+hledger 1.9.1                     April 2018                hledger_timedot(5)