packages feed

hledger 1.3.1 → 1.4

raw patch · 70 files changed

+5781/−4346 lines, 70 filesdep +Diffdep +utility-htdep −ghc-primdep −old-localedep −shakespeare-textdep ~ansi-terminaldep ~hledger-libdep ~megaparsecPVP ok

version bump matches the API change (PVP)

Dependencies added: Diff, utility-ht

Dependencies removed: ghc-prim, old-locale, shakespeare-text

Dependency ranges changed: ansi-terminal, hledger-lib, megaparsec, shakespeare, time

API changes (from Hackage documentation)

- Hledger.Cli.Accounts: accounts :: CliOpts -> Journal -> IO ()
- Hledger.Cli.Accounts: accountsmode :: Mode RawOpts
- Hledger.Cli.Accounts: tests_Hledger_Cli_Accounts :: Test
- Hledger.Cli.Add: EntryState :: CliOpts -> [String] -> Day -> Day -> Journal -> Maybe Transaction -> [Posting] -> EntryState
- Hledger.Cli.Add: RestartTransactionException :: RestartTransactionException
- Hledger.Cli.Add: [esArgs] :: EntryState -> [String]
- Hledger.Cli.Add: [esDefDate] :: EntryState -> Day
- Hledger.Cli.Add: [esJournal] :: EntryState -> Journal
- Hledger.Cli.Add: [esOpts] :: EntryState -> CliOpts
- Hledger.Cli.Add: [esPostings] :: EntryState -> [Posting]
- Hledger.Cli.Add: [esSimilarTransaction] :: EntryState -> Maybe Transaction
- Hledger.Cli.Add: [esToday] :: EntryState -> Day
- Hledger.Cli.Add: accountCompleter :: Journal -> String -> CompletionFunc IO
- Hledger.Cli.Add: accountWizard :: EntryState -> Wizard Haskeline String
- Hledger.Cli.Add: add :: CliOpts -> Journal -> IO ()
- Hledger.Cli.Add: addmode :: Mode RawOpts
- Hledger.Cli.Add: amountAndCommentWizard :: EntryState -> Wizard Haskeline (Amount, Text)
- Hledger.Cli.Add: amountCompleter :: String -> CompletionFunc IO
- Hledger.Cli.Add: appendToJournalFileOrStdout :: FilePath -> String -> IO ()
- Hledger.Cli.Add: capitalize :: String -> String
- Hledger.Cli.Add: compareDescriptions :: Text -> Text -> Double
- Hledger.Cli.Add: compareStrings :: String -> String -> Double
- Hledger.Cli.Add: completer :: [String] -> String -> CompletionFunc IO
- Hledger.Cli.Add: confirmedTransactionWizard :: EntryState -> Wizard Haskeline Transaction
- Hledger.Cli.Add: data EntryState
- Hledger.Cli.Add: data RestartTransactionException
- Hledger.Cli.Add: dateAndCodeWizard :: EntryState -> Wizard Haskeline (Day, Text)
- Hledger.Cli.Add: dateCompleter :: String -> CompletionFunc IO
- Hledger.Cli.Add: defEntryState :: EntryState
- Hledger.Cli.Add: defaultTo' :: a -> Wizard Haskeline a -> Wizard Haskeline a
- Hledger.Cli.Add: descriptionAndCommentWizard :: EntryState -> Wizard Haskeline (Text, Text)
- Hledger.Cli.Add: descriptionCompleter :: Journal -> String -> CompletionFunc IO
- Hledger.Cli.Add: ensureOneNewlineTerminated :: String -> String
- Hledger.Cli.Add: getAndAddTransactions :: EntryState -> IO ()
- Hledger.Cli.Add: green :: [Char] -> [Char]
- Hledger.Cli.Add: instance GHC.Exception.Exception Hledger.Cli.Add.RestartTransactionException
- Hledger.Cli.Add: instance GHC.Show.Show Hledger.Cli.Add.EntryState
- Hledger.Cli.Add: instance GHC.Show.Show Hledger.Cli.Add.RestartTransactionException
- Hledger.Cli.Add: journalAddTransaction :: Journal -> CliOpts -> Transaction -> IO Journal
- Hledger.Cli.Add: letterPairs :: [a] -> [[a]]
- Hledger.Cli.Add: maybeExit :: Wizard Haskeline String -> Wizard Haskeline String
- Hledger.Cli.Add: maybeRestartTransaction :: Wizard Haskeline String -> Wizard Haskeline String
- Hledger.Cli.Add: postingWizard :: EntryState -> Wizard Haskeline (Maybe Posting)
- Hledger.Cli.Add: postingsBalanced :: [Posting] -> Bool
- Hledger.Cli.Add: postingsWizard :: EntryState -> Wizard Haskeline [Posting]
- Hledger.Cli.Add: registerFromString :: String -> IO String
- Hledger.Cli.Add: showDefault :: [Char] -> [Char]
- Hledger.Cli.Add: showHelp :: IO ()
- Hledger.Cli.Add: similarTransaction :: EntryState -> Text -> Maybe Transaction
- Hledger.Cli.Add: transactionWizard :: EntryState -> Wizard Haskeline Transaction
- Hledger.Cli.Add: transactionsSimilarTo :: Journal -> Query -> Text -> [(Double, Transaction)]
- Hledger.Cli.Add: withCompletion :: (:<:) WithSettings b => CompletionFunc IO -> Wizard b a -> Wizard b a
- Hledger.Cli.Add: wordLetterPairs :: String -> [[Char]]
- Hledger.Cli.Balance: balance :: CliOpts -> Journal -> IO ()
- Hledger.Cli.Balance: balanceReportAsTable :: ReportOpts -> MultiBalanceReport -> Table String String MixedAmount
- Hledger.Cli.Balance: balanceReportAsText :: ReportOpts -> BalanceReport -> String
- Hledger.Cli.Balance: balanceReportItemAsText :: ReportOpts -> StringFormat -> BalanceReportItem -> [String]
- Hledger.Cli.Balance: balancemode :: Mode RawOpts
- Hledger.Cli.Balance: multiBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> String
- Hledger.Cli.Balance: renderBalanceReportTable :: ReportOpts -> Table String String MixedAmount -> String
- Hledger.Cli.Balance: tests_Hledger_Cli_Balance :: Test
- Hledger.Cli.Balancesheet: balancesheet :: CliOpts -> Journal -> IO ()
- Hledger.Cli.Balancesheet: balancesheetmode :: Mode RawOpts
- Hledger.Cli.Balancesheet: tests_Hledger_Cli_Balancesheet :: Test
- Hledger.Cli.Cashflow: cashflow :: CliOpts -> Journal -> IO ()
- Hledger.Cli.Cashflow: cashflowmode :: Mode RawOpts
- Hledger.Cli.Cashflow: tests_Hledger_Cli_Cashflow :: Test
- Hledger.Cli.CliOptions: [alias_] :: CliOpts -> [String]
- Hledger.Cli.CliOptions: [ignore_assertions_] :: CliOpts -> Bool
- Hledger.Cli.CliOptions: [rules_file_] :: CliOpts -> Maybe FilePath
- Hledger.Cli.Help: help' :: CliOpts -> IO ()
- Hledger.Cli.Help: helpmode :: Mode RawOpts
- Hledger.Cli.Histogram: activitymode :: Mode RawOpts
- Hledger.Cli.Histogram: barchar :: Char
- Hledger.Cli.Histogram: countBar :: Foldable t => t a -> [Char]
- Hledger.Cli.Histogram: histogram :: CliOpts -> Journal -> IO ()
- Hledger.Cli.Histogram: printDayWith :: (PrintfType t, PrintfArg t1) => (t2 -> t1) -> (DateSpan, t2) -> t
- Hledger.Cli.Histogram: showHistogram :: ReportOpts -> Query -> Journal -> String
- Hledger.Cli.Incomestatement: incomestatement :: CliOpts -> Journal -> IO ()
- Hledger.Cli.Incomestatement: incomestatementmode :: Mode RawOpts
- Hledger.Cli.Incomestatement: tests_Hledger_Cli_Incomestatement :: Test
- Hledger.Cli.Info: info' :: CliOpts -> IO ()
- Hledger.Cli.Info: infomode :: Mode RawOpts
- Hledger.Cli.Main: builtinCommandNames :: [String]
- Hledger.Cli.Main: builtinCommands :: [Mode RawOpts]
- Hledger.Cli.Main: commandsFromCommandsList :: String -> [String]
- Hledger.Cli.Main: commandsListTemplate :: String
- Hledger.Cli.Main: knownCommands :: [String]
- Hledger.Cli.Main: oldconvertmode :: Mode RawOpts
- Hledger.Cli.Main: printCommandsList :: [String] -> IO ()
- Hledger.Cli.Man: man :: CliOpts -> IO ()
- Hledger.Cli.Man: manmode :: Mode RawOpts
- Hledger.Cli.Print: originalTransaction :: Transaction -> Transaction
- Hledger.Cli.Print: print' :: CliOpts -> Journal -> IO ()
- Hledger.Cli.Print: printmode :: Mode RawOpts
- Hledger.Cli.Print: tests_Hledger_Cli_Print :: Test
- Hledger.Cli.Register: postingsReportAsText :: CliOpts -> PostingsReport -> String
- Hledger.Cli.Register: postingsReportItemAsText :: CliOpts -> Int -> Int -> PostingsReportItem -> String
- Hledger.Cli.Register: register :: CliOpts -> Journal -> IO ()
- Hledger.Cli.Register: registermode :: Mode RawOpts
- Hledger.Cli.Register: tests_Hledger_Cli_Register :: Test
- Hledger.Cli.Stats: stats :: CliOpts -> Journal -> IO ()
- Hledger.Cli.Stats: statsmode :: Mode RawOpts
- Hledger.Cli.Tests: test' :: CliOpts -> IO ()
- Hledger.Cli.Tests: testmode :: Mode RawOpts
+ Hledger.Cli.CliOptions: [inputopts_] :: CliOpts -> InputOpts
+ Hledger.Cli.CliOptions: hledgerExecutablesInPath :: IO [String]
+ Hledger.Cli.CliOptions: likelyExecutablesInPath :: IO [String]
+ Hledger.Cli.CliOptions: outputFileFlag :: Flag RawOpts
+ Hledger.Cli.CliOptions: outputFormatFlag :: Flag RawOpts
+ Hledger.Cli.CliOptions: replaceNumericFlags :: [String] -> [String]
+ Hledger.Cli.Commands: builtinCommandNames :: [String]
+ Hledger.Cli.Commands: builtinCommands :: [(Mode RawOpts, CliOpts -> Journal -> IO ())]
+ Hledger.Cli.Commands: findCommand :: String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ())
+ Hledger.Cli.Commands: printCommandsList :: [String] -> IO ()
+ Hledger.Cli.Commands: tests_Hledger_Cli_Commands :: Test
+ Hledger.Cli.Commands.Accounts: accounts :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Accounts: accountsmode :: Mode RawOpts
+ Hledger.Cli.Commands.Accounts: tests_Hledger_Cli_Commands_Accounts :: Test
+ Hledger.Cli.Commands.Activity: activity :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Activity: activitymode :: Mode RawOpts
+ Hledger.Cli.Commands.Activity: barchar :: Char
+ Hledger.Cli.Commands.Activity: countBar :: Foldable t => t a -> [Char]
+ Hledger.Cli.Commands.Activity: printDayWith :: (PrintfType t, PrintfArg t1) => (t2 -> t1) -> (DateSpan, t2) -> t
+ Hledger.Cli.Commands.Activity: showHistogram :: ReportOpts -> Query -> Journal -> String
+ Hledger.Cli.Commands.Add: add :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Add: addmode :: Mode RawOpts
+ Hledger.Cli.Commands.Add: appendToJournalFileOrStdout :: FilePath -> String -> IO ()
+ Hledger.Cli.Commands.Add: instance GHC.Exception.Exception Hledger.Cli.Commands.Add.RestartTransactionException
+ Hledger.Cli.Commands.Add: instance GHC.Show.Show Hledger.Cli.Commands.Add.EntryState
+ Hledger.Cli.Commands.Add: instance GHC.Show.Show Hledger.Cli.Commands.Add.RestartTransactionException
+ Hledger.Cli.Commands.Add: journalAddTransaction :: Journal -> CliOpts -> Transaction -> IO Journal
+ Hledger.Cli.Commands.Add: transactionsSimilarTo :: Journal -> Query -> Text -> [(Double, Transaction)]
+ Hledger.Cli.Commands.Balance: balance :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Balance: balanceReportAsTable :: ReportOpts -> MultiBalanceReport -> Table String String MixedAmount
+ Hledger.Cli.Commands.Balance: balanceReportAsText :: ReportOpts -> BalanceReport -> String
+ Hledger.Cli.Commands.Balance: balanceReportItemAsText :: ReportOpts -> StringFormat -> BalanceReportItem -> [String]
+ Hledger.Cli.Commands.Balance: balancemode :: Mode RawOpts
+ Hledger.Cli.Commands.Balance: multiBalanceReportAsCsv :: ReportOpts -> MultiBalanceReport -> CSV
+ Hledger.Cli.Commands.Balance: multiBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> String
+ Hledger.Cli.Commands.Balance: renderBalanceReportTable :: ReportOpts -> Table String String MixedAmount -> String
+ Hledger.Cli.Commands.Balance: tests_Hledger_Cli_Commands_Balance :: Test
+ Hledger.Cli.Commands.Balancesheet: balancesheet :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Balancesheet: balancesheetmode :: Mode RawOpts
+ Hledger.Cli.Commands.Balancesheet: tests_Hledger_Cli_Commands_Balancesheet :: Test
+ Hledger.Cli.Commands.Balancesheetequity: balancesheetequity :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Balancesheetequity: balancesheetequitymode :: Mode RawOpts
+ Hledger.Cli.Commands.Cashflow: cashflow :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Cashflow: cashflowmode :: Mode RawOpts
+ Hledger.Cli.Commands.Cashflow: tests_Hledger_Cli_Commands_Cashflow :: Test
+ Hledger.Cli.Commands.Checkdates: checkdates :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Checkdates: checkdatesmode :: Mode RawOpts
+ Hledger.Cli.Commands.Checkdates: tests_Hledger_Cli_Commands_Checkdates :: Test
+ Hledger.Cli.Commands.Checkdupes: checkdupes :: t -> Journal -> IO ()
+ Hledger.Cli.Commands.Checkdupes: checkdupesmode :: Mode RawOpts
+ Hledger.Cli.Commands.Equity: equity :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Equity: equitymode :: Mode RawOpts
+ Hledger.Cli.Commands.Help: help' :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Help: helpmode :: Mode RawOpts
+ Hledger.Cli.Commands.Import: importcmd :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Import: importmode :: Mode RawOpts
+ Hledger.Cli.Commands.Incomestatement: incomestatement :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Incomestatement: incomestatementmode :: Mode RawOpts
+ Hledger.Cli.Commands.Incomestatement: tests_Hledger_Cli_Commands_Incomestatement :: Test
+ Hledger.Cli.Commands.Prices: prices :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Prices: pricesmode :: Mode RawOpts
+ Hledger.Cli.Commands.Print: originalTransaction :: Transaction -> Transaction
+ Hledger.Cli.Commands.Print: print' :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Print: printmode :: Mode RawOpts
+ Hledger.Cli.Commands.Print: tests_Hledger_Cli_Commands_Print :: Test
+ Hledger.Cli.Commands.Printunique: printunique :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Printunique: printuniquemode :: Mode RawOpts
+ Hledger.Cli.Commands.Register: postingsReportAsText :: CliOpts -> PostingsReport -> String
+ Hledger.Cli.Commands.Register: postingsReportItemAsText :: CliOpts -> Int -> Int -> PostingsReportItem -> String
+ Hledger.Cli.Commands.Register: register :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Register: registermode :: Mode RawOpts
+ Hledger.Cli.Commands.Register: tests_Hledger_Cli_Commands_Register :: Test
+ Hledger.Cli.Commands.Registermatch: registermatch :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Registermatch: registermatchmode :: Mode RawOpts
+ Hledger.Cli.Commands.Rewrite: instance Data.Foldable.Foldable Hledger.Cli.Commands.Rewrite.DiffLine
+ Hledger.Cli.Commands.Rewrite: instance Data.Traversable.Traversable Hledger.Cli.Commands.Rewrite.DiffLine
+ Hledger.Cli.Commands.Rewrite: instance GHC.Base.Functor Hledger.Cli.Commands.Rewrite.DiffLine
+ Hledger.Cli.Commands.Rewrite: instance GHC.Show.Show a => GHC.Show.Show (Hledger.Cli.Commands.Rewrite.DiffLine a)
+ Hledger.Cli.Commands.Rewrite: rewrite :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Rewrite: rewritemode :: Mode RawOpts
+ Hledger.Cli.Commands.Stats: stats :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Stats: statsmode :: Mode RawOpts
+ Hledger.Cli.Commands.Tags: tags :: CliOpts -> Journal -> IO ()
+ Hledger.Cli.Commands.Tags: tagsmode :: Mode RawOpts
+ Hledger.Cli.DocFiles: runPagerForTopic :: FilePath -> Topic -> IO ()
+ Hledger.Cli.Utils: anonymiseByOpts :: CliOpts -> Journal -> Journal
+ Hledger.Cli.Utils: pivotByOpts :: CliOpts -> Journal -> Journal
- Hledger.Cli.CliOptions: CliOpts :: RawOpts -> String -> [FilePath] -> Maybe FilePath -> Maybe FilePath -> Maybe String -> [String] -> Bool -> Int -> Bool -> Maybe String -> Int -> ReportOpts -> CliOpts
+ Hledger.Cli.CliOptions: CliOpts :: RawOpts -> String -> [FilePath] -> InputOpts -> ReportOpts -> Maybe FilePath -> Maybe String -> Int -> Bool -> Maybe String -> Int -> CliOpts
- Hledger.Cli.CompoundBalanceCommand: CompoundBalanceCommandSpec :: String -> [String] -> String -> String -> [(String, Journal -> Query)] -> BalanceType -> CompoundBalanceCommandSpec
+ Hledger.Cli.CompoundBalanceCommand: CompoundBalanceCommandSpec :: String -> [String] -> String -> String -> [(String, Journal -> Query, Maybe NormalBalance)] -> BalanceType -> CompoundBalanceCommandSpec
- Hledger.Cli.CompoundBalanceCommand: [cbcqueries] :: CompoundBalanceCommandSpec -> [(String, Journal -> Query)]
+ Hledger.Cli.CompoundBalanceCommand: [cbcqueries] :: CompoundBalanceCommandSpec -> [(String, Journal -> Query, Maybe NormalBalance)]

Files

CHANGES view
@@ -2,6 +2,82 @@ See also the project change log.  +# 1.4 (2017/9/30)++* cli: a @FILE argument reads flags & args from FILE, one per line++* cli: reorganized commands list, added some new command aliases:+  accounts: a+  balance:  b+  print:    p, txns+  register: r++* cli: accept -NUM as a shortcut for --depth=NUM (eg: -2)++* cli: improve command-line help for --date2 (#604)++* cli: make --help and -h the same, drop --man and --info for now (#579)++* help: offers multiple formats, accepts topic substrings.+  The separate info/man commands have been dropped. help now+  chooses an appropriate documentation format as follows: +  - it uses info if available, +  - otherwise man if available, +  - otherwise $PAGER if defined, +  - otherwise less if available, +  - otherwise it prints on stdout+  - (and it always prints on stdout when piped). +  You can override this with the `--info`/`--man`/`--pager`/`--cat` flags.+  (#579)++* bal/bs/cf/is: --sort-amount/-S sorts by largest amount instead of+  account name++* bs/cf/is: support --output-file and --output-format=txt|csv+  The CSV output should be reasonably ok for dragging into a+  spreadsheet and reformatting.++* bal/bs/cf/is: consistent double space between columns, consistent+  single final blank line.  Previously, amounts wider than the column+  headings would be separated by only a single space.++* bs/is: don't let an empty subreport disable the grand totals (fixes #588)++* cf: exclude asset accounts with ":fixed" in their name (Christian G. Warden, Simon Michael, #584)++* new balancesheetequity command: like balancesheet but also shows+  equity accounts (Nicholas Niro)++* new import command: adds new transactions seen in one or more input+  files to the main journal file++* print: --new shows only transactions added since last time+  (saves state in .latest.JOURNALFILE file)++* new tags command: lists tags in matched transactions++* most addons formerly shipped in bin/ are now builtin commands. These+  include: check-dates, check-dupes, equity, prices, print-unique,+  register-match, rewrite.++* refactor: new Commands module and subdirectory.+  Builtin commands are now gathered more tightly in a single module,+  Hledger.Cli.Commands, facilitating change.  The legacy "convert"+  command has been dropped.++* refactor: BalanceView -> CompoundBalanceCommand++* deps: drop support for directory < 1.2++* deps: allow ansi-terminal 0.7++* deps: drop oldtime flag, require time 1.5+++* deps: simplify shakespeare bounds++* deps: remove ghc < 7.6 support++ # 1.3.1 (2017/8/25)  * bs/is: don't let an empty subreport disable the grand totals (#588)
Hledger/Cli.hs view
@@ -10,20 +10,8 @@ {-# LANGUAGE OverloadedStrings #-}  module Hledger.Cli (-                     module Hledger.Cli.Accounts,-                     module Hledger.Cli.Add,-                     module Hledger.Cli.Balance,-                     module Hledger.Cli.Balancesheet,-                     module Hledger.Cli.Cashflow,-                     module Hledger.Cli.Help,-                     module Hledger.Cli.Histogram,-                     module Hledger.Cli.Incomestatement,-                     module Hledger.Cli.Info,-                     module Hledger.Cli.Man,-                     module Hledger.Cli.Print,-                     module Hledger.Cli.Register,-                     module Hledger.Cli.Stats,                      module Hledger.Cli.CliOptions,+                     module Hledger.Cli.Commands,                      module Hledger.Cli.DocFiles,                      module Hledger.Cli.Utils,                      module Hledger.Cli.Version,@@ -32,416 +20,13 @@                      module System.Console.CmdArgs.Explicit               ) where-import Data.Monoid ((<>))-import Data.Text (Text)-import qualified Data.Text as T-import Data.Time.Calendar import System.Console.CmdArgs.Explicit hiding (Name) -- don't clash with hledger-ui-import Test.HUnit  import Hledger-import Hledger.Cli.Accounts-import Hledger.Cli.Add-import Hledger.Cli.Balance-import Hledger.Cli.Balancesheet-import Hledger.Cli.Cashflow-import Hledger.Cli.Histogram-import Hledger.Cli.Help-import Hledger.Cli.Incomestatement-import Hledger.Cli.Info-import Hledger.Cli.Man-import Hledger.Cli.Print-import Hledger.Cli.Register-import Hledger.Cli.Stats import Hledger.Cli.CliOptions+import Hledger.Cli.Commands import Hledger.Cli.DocFiles import Hledger.Cli.Utils import Hledger.Cli.Version --tests_Hledger_Cli :: Test-tests_Hledger_Cli = TestList- [-    tests_Hledger-   -- ,tests_Hledger_Cli_Add-   ,tests_Hledger_Cli_Balance-   ,tests_Hledger_Cli_Balancesheet-   ,tests_Hledger_Cli_Cashflow-   -- ,tests_Hledger_Cli_Histogram-   ,tests_Hledger_Cli_Incomestatement-   ,tests_Hledger_Cli_CliOptions-   -- ,tests_Hledger_Cli_Print-   ,tests_Hledger_Cli_Register-   -- ,tests_Hledger_Cli_Stats---   ,"apply account directive" ~: -      let ignoresourcepos j = j{jtxns=map (\t -> t{tsourcepos=nullsourcepos}) (jtxns j)} in-      let sameParse str1 str2 = do j1 <- readJournal Nothing Nothing True Nothing str1 >>= either error' (return . ignoresourcepos)-                                   j2 <- readJournal Nothing Nothing True Nothing str2 >>= either error' (return . ignoresourcepos)-                                   j1 `is` j2{jlastreadtime=jlastreadtime j1, jfiles=jfiles j1} --, jparsestate=jparsestate j1}-      in sameParse-                           ("2008/12/07 One\n  alpha  $-1\n  beta  $1\n" <>-                            "apply account outer\n2008/12/07 Two\n  aigh  $-2\n  bee  $2\n" <>-                            "apply account inner\n2008/12/07 Three\n  gamma  $-3\n  delta  $3\n" <>-                            "end apply account\n2008/12/07 Four\n  why  $-4\n  zed  $4\n" <>-                            "end apply account\n2008/12/07 Five\n  foo  $-5\n  bar  $5\n"-                           )-                           ("2008/12/07 One\n  alpha  $-1\n  beta  $1\n" <>-                            "2008/12/07 Two\n  outer:aigh  $-2\n  outer:bee  $2\n" <>-                            "2008/12/07 Three\n  outer:inner:gamma  $-3\n  outer:inner:delta  $3\n" <>-                            "2008/12/07 Four\n  outer:why  $-4\n  outer:zed  $4\n" <>-                            "2008/12/07 Five\n  foo  $-5\n  bar  $5\n"-                           )--   ,"apply account directive should preserve \"virtual\" posting type" ~: do-      j <- readJournal Nothing Nothing True Nothing "apply account test\n2008/12/07 One\n  (from)  $-1\n  (to)  $1\n" >>= either error' return-      let p = head $ tpostings $ head $ jtxns j-      assertBool "" $ paccount p == "test:from"-      assertBool "" $ ptype p == VirtualPosting--   ,"account aliases" ~: do-      j <- readJournal Nothing Nothing True Nothing "!alias expenses = equity:draw:personal\n1/1\n (expenses:food)  1\n" >>= either error' return-      let p = head $ tpostings $ head $ jtxns j-      assertBool "" $ paccount p == "equity:draw:personal:food"--  ,"ledgerAccountNames" ~:-    ledgerAccountNames ledger7 `is`-     ["assets","assets:cash","assets:checking","assets:saving","equity","equity:opening balances",-      "expenses","expenses:food","expenses:food:dining","expenses:phone","expenses:vacation",-      "liabilities","liabilities:credit cards","liabilities:credit cards:discover"]--  -- ,"journalCanonicaliseAmounts" ~:-  --  "use the greatest precision" ~:-  --   (map asprecision $ journalAmountAndPriceCommodities $ journalCanonicaliseAmounts $ journalWithAmounts ["1","2.00"]) `is` [2,2]--  -- don't know what this should do-  -- ,"elideAccountName" ~: do-  --    (elideAccountName 50 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa"-  --     `is` "aa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa")-  --    (elideAccountName 20 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa"-  --     `is` "aa:aa:aaaaaaaaaaaaaa")--  ,"default year" ~: do-    j <- readJournal Nothing Nothing True Nothing defaultyear_journal_txt >>= either error' return-    tdate (head $ jtxns j) `is` fromGregorian 2009 1 1-    return ()--  ,"show dollars" ~: showAmount (usd 1) ~?= "$1.00"--  ,"show hours" ~: showAmount (hrs 1) ~?= "1.00h"-- ]----- fixtures/test data---- date1 = parsedate "2008/11/26"--- t1 = LocalTime date1 midday--{--samplejournal = readJournal' sample_journal_str--sample_journal_str = unlines- ["; A sample journal file."- ,";"- ,"; Sets up this account tree:"- ,"; assets"- ,";   bank"- ,";     checking"- ,";     saving"- ,";   cash"- ,"; expenses"- ,";   food"- ,";   supplies"- ,"; income"- ,";   gifts"- ,";   salary"- ,"; liabilities"- ,";   debts"- ,""- ,"2008/01/01 income"- ,"    assets:bank:checking  $1"- ,"    income:salary"- ,""- ,"2008/06/01 gift"- ,"    assets:bank:checking  $1"- ,"    income:gifts"- ,""- ,"2008/06/02 save"- ,"    assets:bank:saving  $1"- ,"    assets:bank:checking"- ,""- ,"2008/06/03 * eat & shop"- ,"    expenses:food      $1"- ,"    expenses:supplies  $1"- ,"    assets:cash"- ,""- ,"2008/12/31 * pay off"- ,"    liabilities:debts  $1"- ,"    assets:bank:checking"- ,""- ,""- ,";final comment"- ]--}--defaultyear_journal_txt :: Text-defaultyear_journal_txt = T.unlines- ["Y2009"- ,""- ,"01/01 A"- ,"    a  $1"- ,"    b"- ]---- write_sample_journal = writeFile "sample.journal" sample_journal_str---- entry2_str = unlines---  ["2007/01/27 * joes diner"---  ,"    expenses:food:dining                      $10.00"---  ,"    expenses:gifts                            $10.00"---  ,"    assets:checking                          $-20.00"---  ,""---  ]---- entry3_str = unlines---  ["2007/01/01 * opening balance"---  ,"    assets:cash                                $4.82"---  ,"    equity:opening balances"---  ,""---  ,"2007/01/01 * opening balance"---  ,"    assets:cash                                $4.82"---  ,"    equity:opening balances"---  ,""---  ,"2007/01/28 coopportunity"---  ,"  expenses:food:groceries                 $47.18"---  ,"  assets:checking"---  ,""---  ]---- periodic_entry1_str = unlines---  ["~ monthly from 2007/2/2"---  ,"  assets:saving            $200.00"---  ,"  assets:checking"---  ,""---  ]---- periodic_entry2_str = unlines---  ["~ monthly from 2007/2/2"---  ,"  assets:saving            $200.00         ;auto savings"---  ,"  assets:checking"---  ,""---  ]---- periodic_entry3_str = unlines---  ["~ monthly from 2007/01/01"---  ,"    assets:cash                                $4.82"---  ,"    equity:opening balances"---  ,""---  ,"~ monthly from 2007/01/01"---  ,"    assets:cash                                $4.82"---  ,"    equity:opening balances"---  ,""---  ]---- journal1_str = unlines---  [""---  ,"2007/01/27 * joes diner"---  ,"  expenses:food:dining                    $10.00"---  ,"  expenses:gifts                          $10.00"---  ,"  assets:checking                        $-20.00"---  ,""---  ,""---  ,"2007/01/28 coopportunity"---  ,"  expenses:food:groceries                 $47.18"---  ,"  assets:checking                        $-47.18"---  ,""---  ,""---  ]---- journal2_str = unlines---  [";comment"---  ,"2007/01/27 * joes diner"---  ,"  expenses:food:dining                    $10.00"---  ,"  assets:checking                        $-47.18"---  ,""---  ]---- journal3_str = unlines---  ["2007/01/27 * joes diner"---  ,"  expenses:food:dining                    $10.00"---  ,";intra-entry comment"---  ,"  assets:checking                        $-47.18"---  ,""---  ]---- journal4_str = unlines---  ["!include \"somefile\""---  ,"2007/01/27 * joes diner"---  ,"  expenses:food:dining                    $10.00"---  ,"  assets:checking                        $-47.18"---  ,""---  ]---- journal5_str = ""---- journal6_str = unlines---  ["~ monthly from 2007/1/21"---  ,"    expenses:entertainment  $16.23        ;netflix"---  ,"    assets:checking"---  ,""---  ,"; 2007/01/01 * opening balance"---  ,";     assets:saving                            $200.04"---  ,";     equity:opening balances                         "---  ,""---  ]---- journal7_str = unlines---  ["2007/01/01 * opening balance"---  ,"    assets:cash                                $4.82"---  ,"    equity:opening balances                         "---  ,""---  ,"2007/01/01 * opening balance"---  ,"    income:interest                                $-4.82"---  ,"    equity:opening balances                         "---  ,""---  ,"2007/01/02 * ayres suites"---  ,"    expenses:vacation                        $179.92"---  ,"    assets:checking                                 "---  ,""---  ,"2007/01/02 * auto transfer to savings"---  ,"    assets:saving                            $200.00"---  ,"    assets:checking                                 "---  ,""---  ,"2007/01/03 * poquito mas"---  ,"    expenses:food:dining                       $4.82"---  ,"    assets:cash                                     "---  ,""---  ,"2007/01/03 * verizon"---  ,"    expenses:phone                            $95.11"---  ,"    assets:checking                                 "---  ,""---  ,"2007/01/03 * discover"---  ,"    liabilities:credit cards:discover         $80.00"---  ,"    assets:checking                                 "---  ,""---  ,"2007/01/04 * blue cross"---  ,"    expenses:health:insurance                 $90.00"---  ,"    assets:checking                                 "---  ,""---  ,"2007/01/05 * village market liquor"---  ,"    expenses:food:dining                       $6.48"---  ,"    assets:checking                                 "---  ,""---  ]--journal7 :: Journal-journal7 = nulljournal {jtxns =-          [-           txnTieKnot Transaction {-             tindex=0,-             tsourcepos=nullsourcepos,-             tdate=parsedate "2007/01/01",-             tdate2=Nothing,-             tstatus=Unmarked,-             tcode="*",-             tdescription="opening balance",-             tcomment="",-             ttags=[],-             tpostings=-                 ["assets:cash" `post` usd 4.82-                 ,"equity:opening balances" `post` usd (-4.82)-                 ],-             tpreceding_comment_lines=""-           }-          ,-           txnTieKnot Transaction {-             tindex=0,-             tsourcepos=nullsourcepos,-             tdate=parsedate "2007/02/01",-             tdate2=Nothing,-             tstatus=Unmarked,-             tcode="*",-             tdescription="ayres suites",-             tcomment="",-             ttags=[],-             tpostings=-                 ["expenses:vacation" `post` usd 179.92-                 ,"assets:checking" `post` usd (-179.92)-                 ],-             tpreceding_comment_lines=""-           }-          ,-           txnTieKnot Transaction {-             tindex=0,-             tsourcepos=nullsourcepos,-             tdate=parsedate "2007/01/02",-             tdate2=Nothing,-             tstatus=Unmarked,-             tcode="*",-             tdescription="auto transfer to savings",-             tcomment="",-             ttags=[],-             tpostings=-                 ["assets:saving" `post` usd 200-                 ,"assets:checking" `post` usd (-200)-                 ],-             tpreceding_comment_lines=""-           }-          ,-           txnTieKnot Transaction {-             tindex=0,-             tsourcepos=nullsourcepos,-             tdate=parsedate "2007/01/03",-             tdate2=Nothing,-             tstatus=Unmarked,-             tcode="*",-             tdescription="poquito mas",-             tcomment="",-             ttags=[],-             tpostings=-                 ["expenses:food:dining" `post` usd 4.82-                 ,"assets:cash" `post` usd (-4.82)-                 ],-             tpreceding_comment_lines=""-           }-          ,-           txnTieKnot Transaction {-             tindex=0,-             tsourcepos=nullsourcepos,-             tdate=parsedate "2007/01/03",-             tdate2=Nothing,-             tstatus=Unmarked,-             tcode="*",-             tdescription="verizon",-             tcomment="",-             ttags=[],-             tpostings=-                 ["expenses:phone" `post` usd 95.11-                 ,"assets:checking" `post` usd (-95.11)-                 ],-             tpreceding_comment_lines=""-           }-          ,-           txnTieKnot Transaction {-             tindex=0,-             tsourcepos=nullsourcepos,-             tdate=parsedate "2007/01/03",-             tdate2=Nothing,-             tstatus=Unmarked,-             tcode="*",-             tdescription="discover",-             tcomment="",-             ttags=[],-             tpostings=-                 ["liabilities:credit cards:discover" `post` usd 80-                 ,"assets:checking" `post` usd (-80)-                 ],-             tpreceding_comment_lines=""-           }-          ]-         }--ledger7 :: Ledger-ledger7 = ledgerFromJournal Any journal7+tests_Hledger_Cli = tests_Hledger_Cli_Commands
− Hledger/Cli/Accounts.hs
@@ -1,67 +0,0 @@-{-|--The @accounts@ command lists account names:--- in flat mode (default), it lists the full names of accounts posted to by matched postings,-  clipped to the specified depth, possibly with leading components dropped.--- in tree mode, it shows the indented short names of accounts posted to by matched postings,-  and their parents, to the specified depth.---}--{-# LANGUAGE OverloadedStrings #-}--module Hledger.Cli.Accounts (-  accountsmode- ,accounts- ,tests_Hledger_Cli_Accounts-) where--import Data.List-import Data.Monoid--- import Data.Text (Text)-import qualified Data.Text as T-import System.Console.CmdArgs.Explicit as C-import Test.HUnit--import Hledger-import Prelude hiding (putStrLn)-import Hledger.Utils.UTF8IOCompat (putStrLn)-import Hledger.Cli.CliOptions----- | Command line options for this command.-accountsmode = (defCommandMode $ ["accounts"] ++ aliases) {-  modeHelp = "show account names" `withAliases` aliases- ,modeHelpSuffix = [-    "This command lists the accounts referenced by matched postings (and in tree mode, their parents as well). The accounts can be depth-clipped (--depth N) or have their leading parts trimmed (--drop N)."-   ]- ,modeGroupFlags = C.Group {-     groupUnnamed = [-      flagNone ["tree"] (\opts -> setboolopt "tree" opts) "show short account names, as a tree"-     ,flagNone ["flat"] (\opts -> setboolopt "flat" opts) "show full account names, as a list (default)"-     ,flagReq  ["drop"] (\s opts -> Right $ setopt "drop" s opts) "N" "flat mode: omit N leading account name parts"-     ]-    ,groupHidden = []-    ,groupNamed = [generalflagsgroup1]-    }- }-  where aliases = []---- | The accounts command.-accounts :: CliOpts -> Journal -> IO ()-accounts CliOpts{reportopts_=ropts} j = do-  d <- getCurrentDay-  let q = queryFromOpts d ropts-      nodepthq = dbg1 "nodepthq" $ filterQuery (not . queryIsDepth) q-      depth    = dbg1 "depth" $ queryDepth $ filterQuery queryIsDepth q-      ps = dbg1 "ps" $ journalPostings $ filterJournalPostings nodepthq j-      as = dbg1 "as" $ nub $ filter (not . T.null) $ map (clipAccountName depth) $ sort $ map paccount ps-      as' | tree_ ropts = expandAccountNames as-          | otherwise   = as-      render a | tree_ ropts = T.replicate (2 * (accountNameLevel a - 1)) " " <> accountLeafName a-               | otherwise   = maybeAccountNameDrop ropts a-  mapM_ (putStrLn . T.unpack . render) as'--tests_Hledger_Cli_Accounts = TestList []
− Hledger/Cli/Add.hs
@@ -1,449 +0,0 @@-{-|-A history-aware add command to help with data entry.-|-}--{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-unused-do-bind #-}-{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable, RecordWildCards, TypeOperators, FlexibleContexts, OverloadedStrings #-}--module Hledger.Cli.Add-where--import Prelude ()-import Prelude.Compat-import Control.Exception as E-import Control.Monad-import Control.Monad.Trans.Class-import Control.Monad.State.Strict (evalState, evalStateT)-import Control.Monad.Trans (liftIO)-import Data.Char (toUpper, toLower)-import Data.Functor.Identity (Identity(..))-import Data.List.Compat-import qualified Data.Set as S-import Data.Maybe-import Data.Text (Text)-import qualified Data.Text as T-import Data.Time.Calendar (Day)-import Data.Typeable (Typeable)-import Safe (headDef, headMay)-import System.Console.CmdArgs.Explicit-import System.Console.Haskeline (runInputT, defaultSettings, setComplete)-import System.Console.Haskeline.Completion-import System.Console.Wizard-import System.Console.Wizard.Haskeline-import System.IO ( stderr, hPutStr, hPutStrLn )-import Text.Megaparsec.Compat-import Text.Printf--import Hledger-import Hledger.Cli.CliOptions-import Hledger.Cli.Register (postingsReportAsText)---addmode = (defCommandMode ["add"]) {-  modeHelp = "prompt for transactions and add them to the journal"- ,modeHelpSuffix = ["Defaults come from previous similar transactions; use query patterns to restrict these."]- ,modeGroupFlags = Group {-     groupUnnamed = [-      flagNone ["no-new-accounts"]  (\opts -> setboolopt "no-new-accounts" opts) "don't allow creating new accounts"-     ]-    ,groupHidden = []-    ,groupNamed = [generalflagsgroup2]-    }- }---- | State used while entering transactions.-data EntryState = EntryState {-   esOpts               :: CliOpts           -- ^ command line options-  ,esArgs               :: [String]          -- ^ command line arguments remaining to be used as defaults-  ,esToday              :: Day               -- ^ today's date-  ,esDefDate            :: Day               -- ^ the default date for next transaction-  ,esJournal            :: Journal           -- ^ the journal we are adding to-  ,esSimilarTransaction :: Maybe Transaction -- ^ the most similar historical txn-  ,esPostings           :: [Posting]         -- ^ postings entered so far in the current txn-  } deriving (Show,Typeable)--defEntryState = EntryState {-   esOpts               = defcliopts-  ,esArgs               = []-  ,esToday              = nulldate-  ,esDefDate            = nulldate-  ,esJournal            = nulljournal-  ,esSimilarTransaction = Nothing-  ,esPostings           = []-}--data RestartTransactionException = RestartTransactionException deriving (Typeable,Show)-instance Exception RestartTransactionException---- data ShowHelpException = ShowHelpException deriving (Typeable,Show)--- instance Exception ShowHelpException---- | Read multiple transactions from the console, prompting for each--- field, and append them to the journal file.  If the journal came--- from stdin, this command has no effect.-add :: CliOpts -> Journal -> IO ()-add opts j-    | journalFilePath j == "-" = return ()-    | otherwise = do-        hPrintf stderr "Adding transactions to journal file %s\n" (journalFilePath j)-        showHelp-        today <- getCurrentDay-        let es = defEntryState{esOpts=opts-                              ,esArgs=map (T.unpack . stripquotes . T.pack) $ listofstringopt "args" $ rawopts_ opts-                              ,esToday=today-                              ,esDefDate=today-                              ,esJournal=j-                              }-        getAndAddTransactions es `E.catch` (\(_::UnexpectedEOF) -> putStr "")--showHelp = hPutStr stderr $ unlines [-     "Any command line arguments will be used as defaults."-    ,"Use tab key to complete, readline keys to edit, enter to accept defaults."-    ,"An optional (CODE) may follow transaction dates."-    ,"An optional ; COMMENT may follow descriptions or amounts."-    ,"If you make a mistake, enter < at any prompt to restart the transaction."-    ,"To end a transaction, enter . when prompted."-    ,"To quit, enter . at a date prompt or press control-d or control-c."-    ]---- | Loop reading transactions from the console, prompting, validating--- and appending each one to the journal file, until end of input or--- ctrl-c (then raise an EOF exception).  If provided, command-line--- arguments are used as defaults; otherwise defaults come from the--- most similar recent transaction in the journal.-getAndAddTransactions :: EntryState -> IO ()-getAndAddTransactions es@EntryState{..} = (do-  mt <- runInputT (setComplete noCompletion defaultSettings) (run $ haskeline $ confirmedTransactionWizard es)-  case mt of-    Nothing -> fail "urk ?"-    Just t -> do-      j <- if debug_ esOpts > 0-           then do hPrintf stderr "Skipping journal add due to debug mode.\n"-                   return esJournal-           else do j' <- journalAddTransaction esJournal esOpts t-                   hPrintf stderr "Saved.\n"-                   return j'-      hPrintf stderr "Starting the next transaction (. or ctrl-D/ctrl-C to quit)\n"-      getAndAddTransactions es{esJournal=j, esDefDate=tdate t}-  )-  `E.catch` (\(_::RestartTransactionException) ->-                 hPrintf stderr "Restarting this transaction.\n" >> getAndAddTransactions es)---- confirmedTransactionWizard :: (ArbitraryIO :<: b, OutputLn :<: b, Line :<: b) => EntryState -> Wizard b Transaction--- confirmedTransactionWizard :: EntryState -> Wizard Haskeline Transaction-confirmedTransactionWizard es@EntryState{..} = do-  t <- transactionWizard es-  -- liftIO $ hPrintf stderr {- "Transaction entered:\n%s" -} (show t)-  output $ show t-  y <- let def = "y" in-       retryMsg "Please enter y or n." $-        parser ((fmap ('y' ==)) . headMay . map toLower . strip) $-        defaultTo' def $ nonEmpty $-        maybeRestartTransaction $-        line $ green $ printf "Save this transaction to the journal ?%s: " (showDefault def)-  if y then return t else throw RestartTransactionException--transactionWizard es@EntryState{..} = do-  (date,code)    <- dateAndCodeWizard es-  let es1@EntryState{esArgs=args1} = es{esArgs=drop 1 esArgs, esDefDate=date}-  (desc,comment) <- descriptionAndCommentWizard es1-  let mbaset = similarTransaction es1 desc-  when (isJust mbaset) $ liftIO $ hPrintf stderr "Using this similar transaction for defaults:\n%s" (show $ fromJust mbaset)-  let es2 = es1{esArgs=drop 1 args1, esSimilarTransaction=mbaset}-      balancedPostingsWizard = do-        ps <- postingsWizard es2{esPostings=[]}-        let t = nulltransaction{tdate=date-                               ,tstatus=Unmarked-                               ,tcode=code-                               ,tdescription=desc-                               ,tcomment=comment-                               ,tpostings=ps-                               }-        case balanceTransaction Nothing t of -- imprecise balancing (?)-          Right t' -> return t'-          Left err -> liftIO (hPutStrLn stderr $ "\n" ++ (capitalize err) ++ "please re-enter.") >> balancedPostingsWizard-  balancedPostingsWizard---- Identify the closest recent match for this description in past transactions.-similarTransaction :: EntryState -> Text -> Maybe Transaction-similarTransaction EntryState{..} desc =-  let q = queryFromOptsOnly esToday $ reportopts_ esOpts-      historymatches = transactionsSimilarTo esJournal q desc-      bestmatch | null historymatches = Nothing-                | otherwise           = Just $ snd $ head historymatches-  in bestmatch--dateAndCodeWizard EntryState{..} = do-  let def = headDef (showDate esDefDate) esArgs-  retryMsg "A valid hledger smart date is required. Eg: 2014/2/14, 14, yesterday." $-   parser (parseSmartDateAndCode esToday) $-   withCompletion (dateCompleter def) $-   defaultTo' def $ nonEmpty $-   maybeExit $-   maybeRestartTransaction $-   -- maybeShowHelp $-   line $ green $ printf "Date%s: " (showDefault def)-    where-      parseSmartDateAndCode refdate s = either (const Nothing) (\(d,c) -> return (fixSmartDate refdate d, c)) edc-          where-            edc = runParser (dateandcodep <* eof) "" $ T.pack $ lowercase s-            dateandcodep :: SimpleTextParser (SmartDate, Text)-            dateandcodep = do-                d <- smartdate-                c <- optional codep-                many spacenonewline-                eof-                return (d, T.pack $ fromMaybe "" c)-      -- defday = fixSmartDate today $ fromparse $ (parse smartdate "" . lowercase) defdate-      -- datestr = showDate $ fixSmartDate defday smtdate--descriptionAndCommentWizard EntryState{..} = do-  let def = headDef "" esArgs-  s <- withCompletion (descriptionCompleter esJournal def) $-       defaultTo' def $ nonEmpty $-       maybeRestartTransaction $-       line $ green $ printf "Description%s: " (showDefault def)-  let (desc,comment) = (T.pack $ strip a, T.pack $ strip $ dropWhile (==';') b) where (a,b) = break (==';') s-  return (desc, comment)--postingsWizard es@EntryState{..} = do-  mp <- postingWizard es-  case mp of Nothing -> return esPostings-             Just p  -> postingsWizard es{esArgs=drop 2 esArgs, esPostings=esPostings++[p]}--postingWizard es@EntryState{..} = do-  acct <- accountWizard es-  if acct `elem` [".",""]-  then case (esPostings, postingsBalanced esPostings) of-         ([],_)    -> liftIO (hPutStrLn stderr "Please enter some postings first.") >> postingWizard es-         (_,False) -> liftIO (hPutStrLn stderr "Please enter more postings to balance the transaction.") >> postingWizard es-         (_,True)  -> return Nothing -- no more postings, end of transaction-  else do-    let es1 = es{esArgs=drop 1 esArgs}-    (amt,comment)  <- amountAndCommentWizard es1-    return $ Just nullposting{paccount=T.pack $ stripbrackets acct-                             ,pamount=Mixed [amt]-                             ,pcomment=comment-                             ,ptype=accountNamePostingType $ T.pack acct-                             }--postingsBalanced :: [Posting] -> Bool-postingsBalanced ps = isRight $ balanceTransaction Nothing nulltransaction{tpostings=ps}--accountWizard EntryState{..} = do-  let pnum = length esPostings + 1-      historicalp = maybe Nothing (Just . (!! (pnum-1)) . (++ (repeat nullposting)) . tpostings) esSimilarTransaction-      historicalacct = case historicalp of Just p  -> showAccountName Nothing (ptype p) (paccount p)-                                           Nothing -> ""-      def = headDef historicalacct esArgs-      endmsg | canfinish && null def = " (or . or enter to finish this transaction)"-             | canfinish             = " (or . to finish this transaction)"-             | otherwise             = ""-  retryMsg "A valid hledger account name is required. Eg: assets:cash, expenses:food:eating out." $-   parser (parseAccountOrDotOrNull def canfinish) $-   withCompletion (accountCompleter esJournal def) $-   defaultTo' def $ -- nonEmpty $-   maybeRestartTransaction $-   line $ green $ printf "Account %d%s%s: " pnum (endmsg::String) (showDefault def)-    where-      canfinish = not (null esPostings) && postingsBalanced esPostings-      parseAccountOrDotOrNull :: String -> Bool -> String -> Maybe String-      parseAccountOrDotOrNull _  _ "."       = dbg1 $ Just "." -- . always signals end of txn-      parseAccountOrDotOrNull "" True ""     = dbg1 $ Just ""  -- when there's no default and txn is balanced, "" also signals end of txn-      parseAccountOrDotOrNull def@(_:_) _ "" = dbg1 $ Just def -- when there's a default, "" means use that-      parseAccountOrDotOrNull _ _ s          = dbg1 $ fmap T.unpack $-        either (const Nothing) validateAccount $-          flip evalState esJournal $ runParserT (accountnamep <* eof) "" (T.pack s) -- otherwise, try to parse the input as an accountname-        where-          validateAccount :: Text -> Maybe Text-          validateAccount t | no_new_accounts_ esOpts && not (t `elem` journalAccountNames esJournal) = Nothing-                            | otherwise = Just t-      dbg1 = id -- strace--amountAndCommentWizard EntryState{..} = do-  let pnum = length esPostings + 1-      (mhistoricalp,followedhistoricalsofar) =-          case esSimilarTransaction of-            Nothing                        -> (Nothing,False)-            Just Transaction{tpostings=ps} -> (if length ps >= pnum then Just (ps !! (pnum-1)) else Nothing-                                              ,all (\(a,b) -> pamount a == pamount b) $ zip esPostings ps)-      def = case (esArgs, mhistoricalp, followedhistoricalsofar) of-              (d:_,_,_)                                             -> d-              (_,Just hp,True)                                      -> showamt $ pamount hp-              _  | pnum > 1 && not (isZeroMixedAmount balancingamt) -> showamt balancingamtfirstcommodity-              _                                                     -> ""-  retryMsg "A valid hledger amount is required. Eg: 1, $2, 3 EUR, \"4 red apples\"." $-   parser parseAmountAndComment $-   withCompletion (amountCompleter def) $-   defaultTo' def $ nonEmpty $-   maybeRestartTransaction $-   line $ green $ printf "Amount  %d%s: " pnum (showDefault def)-    where-      parseAmountAndComment s = either (const Nothing) Just $-                                runParser-                                  (evalStateT (amountandcommentp <* eof) nodefcommodityj)-                                  ""-                                  (T.pack s)-      nodefcommodityj = esJournal{jparsedefaultcommodity=Nothing}-      amountandcommentp :: JournalParser Identity (Amount, Text)-      amountandcommentp = do-        a <- amountp-        lift (many spacenonewline)-        c <- T.pack <$> fromMaybe "" `fmap` optional (char ';' >> many anyChar)-        -- eof-        return (a,c)-      balancingamt = negate $ sum $ map pamount realps where realps = filter isReal esPostings-      balancingamtfirstcommodity = Mixed $ take 1 $ amounts balancingamt-      showamt =-        showMixedAmountWithPrecision-                  -- what should this be ?-                  -- 1 maxprecision (show all decimal places or none) ?-                  -- 2 maxprecisionwithpoint (show all decimal places or .0 - avoids some but not all confusion with thousands separators) ?-                  -- 3 canonical precision for this commodity in the journal ?-                  -- 4 maximum precision entered so far in this transaction ?-                  -- 5 3 or 4, whichever would show the most decimal places ?-                  -- I think 1 or 4, whichever would show the most decimal places-                  maxprecisionwithpoint-  ---  -- let -- (amt,comment) = (strip a, strip $ dropWhile (==';') b) where (a,b) = break (==';') amtcmt-      -- a           = fromparse $ runParser (amountp <|> return missingamt) (jparsestate esJournal) "" amt-  --     awithoutjps = fromparse $ runParser (amountp <|> return missingamt) mempty              "" amt-  --     defamtaccepted = Just (showAmount a) == mdefamt-  --     es2 = if defamtaccepted then es1 else es1{esHistoricalPostings=Nothing}-  --     mdefaultcommodityapplied = if acommodity a == acommodity awithoutjps then Nothing else Just $ acommodity a-  -- when (isJust mdefaultcommodityapplied) $-  --      liftIO $ hPutStrLn stderr $ printf "using default commodity (%s)" (fromJust mdefaultcommodityapplied)--maybeExit = parser (\s -> if s=="." then throw UnexpectedEOF else Just s)--maybeRestartTransaction = parser (\s -> if s=="<" then throw RestartTransactionException else Just s)---- maybeShowHelp :: Wizard Haskeline String -> Wizard Haskeline String--- maybeShowHelp wizard = maybe (liftIO showHelp >> wizard) return $---                        parser (\s -> if s=="?" then Nothing else Just s) wizard---- Completion helpers--dateCompleter :: String -> CompletionFunc IO-dateCompleter = completer ["today","tomorrow","yesterday"]--descriptionCompleter :: Journal -> String -> CompletionFunc IO-descriptionCompleter j = completer (map T.unpack $ journalDescriptions j)--accountCompleter :: Journal -> String -> CompletionFunc IO-accountCompleter j = completer (map T.unpack $ journalAccountNamesUsed j)--amountCompleter :: String -> CompletionFunc IO-amountCompleter = completer []---- | Generate a haskeline completion function from the given--- completions and default, that case insensitively completes with--- prefix matches, or infix matches above a minimum length, or--- completes the null string with the default.-completer :: [String] -> String -> CompletionFunc IO-completer completions def = completeWord Nothing "" completionsFor-    where-      simpleCompletion' s = (simpleCompletion s){isFinished=False}-      completionsFor "" = return [simpleCompletion' def]-      completionsFor i  = return (map simpleCompletion' ciprefixmatches)-          where-            ciprefixmatches = [c | c <- completions, i `isPrefixOf` c]-            -- mixed-case completions require haskeline > 0.7.1.2-            -- ciprefixmatches = [c | c <- completions, lowercase i `isPrefixOf` lowercase c]-------------------------------------------------------------------------------------- utilities--defaultTo' = flip defaultTo--withCompletion f = withSettings (setComplete f defaultSettings)--green s = "\ESC[1;32m\STX"++s++"\ESC[0m\STX"--showDefault "" = ""-showDefault s = " [" ++ s ++ "]"---- | Append this transaction to the journal's file and transaction list.-journalAddTransaction :: Journal -> CliOpts -> Transaction -> IO Journal-journalAddTransaction j@Journal{jtxns=ts} opts t = do-  let f = journalFilePath j-  appendToJournalFileOrStdout f $ showTransactionUnelided t-    -- unelided shows all amounts explicitly, in case there's a price, cf #283-  when (debug_ opts > 0) $ do-    putStrLn $ printf "\nAdded transaction to %s:" f-    putStrLn =<< registerFromString (show t)-  return j{jtxns=ts++[t]}---- | Append a string, typically one or more transactions, to a journal--- file, or if the file is "-", dump it to stdout.  Tries to avoid--- excess whitespace.-appendToJournalFileOrStdout :: FilePath -> String -> IO ()-appendToJournalFileOrStdout f s-  | f == "-"  = putStr s'-  | otherwise = appendFile f s'-  where s' = "\n" ++ ensureOneNewlineTerminated s---- | Replace a string's 0 or more terminating newlines with exactly one.-ensureOneNewlineTerminated :: String -> String-ensureOneNewlineTerminated = (++"\n") . reverse . dropWhile (=='\n') . reverse---- | Convert a string of journal data into a register report.-registerFromString :: String -> IO String-registerFromString s = do-  d <- getCurrentDay-  j <- readJournal' $ T.pack s-  return $ postingsReportAsText opts $ postingsReport ropts (queryFromOpts d ropts) j-      where-        ropts = defreportopts{empty_=True}-        opts = defcliopts{reportopts_=ropts}--capitalize :: String -> String-capitalize "" = ""-capitalize (c:cs) = toUpper c : cs---- | Find the most similar and recent transactions matching the given--- transaction description and report query.  Transactions are listed--- with their "relevancy" score, most relevant first.-transactionsSimilarTo :: Journal -> Query -> Text -> [(Double,Transaction)]-transactionsSimilarTo j q desc =-    sortBy compareRelevanceAndRecency-               $ filter ((> threshold).fst)-               [(compareDescriptions desc $ tdescription t, t) | t <- ts]-    where-      compareRelevanceAndRecency (n1,t1) (n2,t2) = compare (n2,tdate t2) (n1,tdate t1)-      ts = filter (q `matchesTransaction`) $ jtxns j-      threshold = 0---- | Return a similarity measure, from 0 to 1, for two transaction--- descriptions.  This is like compareStrings, but first strips out--- any numbers, to improve accuracy eg when there are bank transaction--- ids from imported data.-compareDescriptions :: Text -> Text -> Double-compareDescriptions s t = compareStrings s' t'-    where s' = simplify $ T.unpack s-          t' = simplify $ T.unpack t-          simplify = filter (not . (`elem` ("0123456789" :: String)))---- | Return a similarity measure, from 0 to 1, for two strings.  This--- was based on Simon White's string similarity algorithm--- (http://www.catalysoft.com/articles/StrikeAMatch.html), later found--- to be https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient,--- modified to handle short strings better.--- Todo: check out http://nlp.fi.muni.cz/raslan/2008/raslan08.pdf#page=14 .-compareStrings :: String -> String -> Double-compareStrings "" "" = 1-compareStrings (_:[]) "" = 0-compareStrings "" (_:[]) = 0-compareStrings (a:[]) (b:[]) = if toUpper a == toUpper b then 1 else 0-compareStrings s1 s2 = 2 * commonpairs / totalpairs-    where-      pairs1      = S.fromList $ wordLetterPairs $ uppercase s1-      pairs2      = S.fromList $ wordLetterPairs $ uppercase s2-      commonpairs = fromIntegral $ S.size $ S.intersection pairs1 pairs2-      totalpairs  = fromIntegral $ S.size pairs1 + S.size pairs2--wordLetterPairs = concatMap letterPairs . words--letterPairs (a:b:rest) = [a,b] : letterPairs (b:rest)-letterPairs _ = []
− Hledger/Cli/Balance.hs
@@ -1,545 +0,0 @@-{-|--A ledger-compatible @balance@ command, with additional support for-multi-column reports.--Here is a description/specification for the balance command.  See also-"Hledger.Reports" -> \"Balance reports\".---/Basic balance report/--With no report interval (@--monthly@ etc.), hledger's balance-command emulates ledger's, showing accounts indented according to-hierarchy, along with their total amount posted (including subaccounts).--Here's an example. With @examples/sample.journal@, which defines the following account tree:--@- assets-   bank-     checking-     saving-   cash- expenses-   food-   supplies- income-   gifts-   salary- liabilities-   debts-@--the basic @balance@ command gives this output:--@- $ hledger -f sample.journal balance-                 $-1  assets-                  $1    bank:saving-                 $-2    cash-                  $2  expenses-                  $1    food-                  $1    supplies-                 $-2  income-                 $-1    gifts-                 $-1    salary-                  $1  liabilities:debts----------------------                   0-@--Subaccounts are displayed indented below their parent. Only the account leaf name (the final part) is shown.-(With @--flat@, account names are shown in full and unindented.)--Each account's \"balance\" is the sum of postings in that account and any subaccounts during the report period.-When the report period includes all transactions, this is equivalent to the account's current balance.--The overall total of the highest-level displayed accounts is shown below the line.-(The @--no-total/-N@ flag prevents this.)--/Eliding and omitting/--Accounts which have a zero balance, and no non-zero subaccount-balances, are normally omitted from the report.-(The @--empty/-E@ flag forces such accounts to be displayed.)-Eg, above @checking@ is omitted because it has a zero balance and no subaccounts.--Accounts which have a single subaccount also being displayed, with the same balance,-are normally elided into the subaccount's line.-(The @--no-elide@ flag prevents this.)-Eg, above @bank@ is elided to @bank:saving@ because it has only a-single displayed subaccount (@saving@) and their balance is the same-($1). Similarly, @liabilities@ is elided to @liabilities:debts@.--/Date limiting/--The default report period is that of the whole journal, including all-known transactions. The @--begin\/-b@, @--end\/-e@, @--period\/-p@-options or @date:@/@date2:@ patterns can be used to report only-on transactions before and/or after specified dates.--/Depth limiting/--The @--depth@ option can be used to limit the depth of the balance report.-Eg, to see just the top level accounts (still including their subaccount balances):--@-$ hledger -f sample.journal balance --depth 1-                 $-1  assets-                  $2  expenses-                 $-2  income-                  $1  liabilities----------------------                   0-@--/Account limiting/--With one or more account pattern arguments, the report is restricted-to accounts whose name matches one of the patterns, plus their parents-and subaccounts. Eg, adding the pattern @o@ to the first example gives:--@- $ hledger -f sample.journal balance o-                  $1  expenses:food-                 $-2  income-                 $-1    gifts-                 $-1    salary----------------------                 $-1-@--* The @o@ pattern matched @food@ and @income@, so they are shown.--* @food@'s parent (@expenses@) is shown even though the pattern didn't-  match it, to clarify the hierarchy. The usual eliding rules cause it to be elided here.--* @income@'s subaccounts are also shown.--/Multi-column balance report/--hledger's balance command will show multiple columns when a reporting-interval is specified (eg with @--monthly@), one column for each sub-period.--There are three kinds of multi-column balance report, indicated by the heading:--* A \"period balance\" (or \"flow\") report (the default) shows the change of account-  balance in each period, which is equivalent to the sum of postings in each-  period. Here, checking's balance increased by 10 in Feb:--  > Change of balance (flow):-  >-  >                  Jan   Feb   Mar-  > assets:checking   20    10    -5--* A \"cumulative balance\" report (with @--cumulative@) shows the accumulated ending balance-  across periods, starting from zero at the report's start date.-  Here, 30 is the sum of checking postings during Jan and Feb:--  > Ending balance (cumulative):-  >-  >                  Jan   Feb   Mar-  > assets:checking   20    30    25--* A \"historical balance\" report (with @--historical/-H@) also shows ending balances,-  but it includes the starting balance from any postings before the report start date.-  Here, 130 is the balance from all checking postings at the end of Feb, including-  pre-Jan postings which created a starting balance of 100:--  > Ending balance (historical):-  >-  >                  Jan   Feb   Mar-  > assets:checking  120   130   125--/Eliding and omitting, 2/--Here's a (imperfect?) specification for the eliding/omitting behaviour:--* Each account is normally displayed on its own line.--* An account less deep than the report's max depth, with just one-interesting subaccount, and the same balance as the subaccount, is-non-interesting, and prefixed to the subaccount's line, unless-@--no-elide@ is in effect.--* An account with a zero inclusive balance and less than two interesting-subaccounts is not displayed at all, unless @--empty@ is in effect.--* Multi-column balance reports show full account names with no eliding-  (like @--flat@). Accounts (and periods) are omitted as described below.--/Which accounts to show in balance reports/--By default:--* single-column: accounts with non-zero balance in report period.-                 (With @--flat@: accounts with non-zero balance and postings.)--* periodic:      accounts with postings and non-zero period balance in any period--* cumulative:    accounts with non-zero cumulative balance in any period--* historical:    accounts with non-zero historical balance in any period--With @-E/--empty@:--* single-column: accounts with postings in report period--* periodic:      accounts with postings in report period--* cumulative:    accounts with postings in report period--* historical:    accounts with non-zero starting balance +-                 accounts with postings in report period--/Which periods (columns) to show in balance reports/--An empty period/column is one where no report account has any postings.-A zero period/column is one where no report account has a non-zero period balance.--Currently,--by default:--* single-column: N/A--* periodic:      all periods within the overall report period,-                 except for leading and trailing empty periods--* cumulative:    all periods within the overall report period,-                 except for leading and trailing empty periods--* historical:    all periods within the overall report period,-                 except for leading and trailing empty periods--With @-E/--empty@:--* single-column: N/A--* periodic:      all periods within the overall report period--* cumulative:    all periods within the overall report period--* historical:    all periods within the overall report period--/What to show in empty cells/--An empty periodic balance report cell is one which has no corresponding postings.-An empty cumulative/historical balance report cell is one which has no correponding-or prior postings, ie the account doesn't exist yet.-Currently, empty cells show 0.---}--{-# LANGUAGE OverloadedStrings #-}--module Hledger.Cli.Balance (-  balancemode- ,balance- ,balanceReportAsText- ,balanceReportItemAsText- ,multiBalanceReportAsText- ,renderBalanceReportTable- ,balanceReportAsTable- ,tests_Hledger_Cli_Balance-) where--import Data.List (intercalate)-import Data.Maybe--- import Data.Monoid-import qualified Data.Text as T-import System.Console.CmdArgs.Explicit as C-import Text.CSV-import Test.HUnit-import Text.Printf (printf)-import Text.Tabular as T-import Text.Tabular.AsciiWide--import Hledger-import Hledger.Cli.CliOptions-import Hledger.Cli.Utils----- | Command line options for this command.-balancemode = (defCommandMode $ ["balance"] ++ aliases) { -- also accept but don't show the common bal alias-  modeHelp = "show accounts and balances" `withAliases` aliases- ,modeGroupFlags = C.Group {-     groupUnnamed = [-      flagNone ["change"] (\opts -> setboolopt "change" opts)-        "show balance change in each period (default)"-     ,flagNone ["cumulative"] (\opts -> setboolopt "cumulative" opts)-        "show balance change accumulated across periods (in multicolumn reports)"-     ,flagNone ["historical","H"] (\opts -> setboolopt "historical" opts)-        "show historical ending balance in each period (includes postings before report start date)\n "-     ,flagNone ["tree"] (\opts -> setboolopt "tree" opts) "show accounts as a tree; amounts include subaccounts (default in simple reports)"-     ,flagNone ["flat"] (\opts -> setboolopt "flat" opts) "show accounts as a list; amounts exclude subaccounts except when account is depth-clipped (default in multicolumn reports)\n "-     ,flagNone ["average","A"] (\opts -> setboolopt "average" opts) "show a row average column (in multicolumn reports)"-     ,flagNone ["row-total","T"] (\opts -> setboolopt "row-total" opts) "show a row total column (in multicolumn reports)"-     ,flagNone ["no-total","N"] (\opts -> setboolopt "no-total" opts) "omit the final total row"-     ,flagReq  ["drop"] (\s opts -> Right $ setopt "drop" s opts) "N" "omit N leading account name parts (in flat mode)"-     ,flagNone ["no-elide"] (\opts -> setboolopt "no-elide" opts) "don't squash boring parent accounts (in tree mode)"-     ,flagReq  ["format"] (\s opts -> Right $ setopt "format" s opts) "FORMATSTR" "use this custom line format (in simple reports)"-     ,flagNone ["pretty-tables"] (\opts -> setboolopt "pretty-tables" opts) "use unicode when displaying tables"-     ]-     ++ outputflags-    ,groupHidden = []-    ,groupNamed = [generalflagsgroup1]-    }- }-  where aliases = ["bal"]---- | The balance command, prints a balance report.-balance :: CliOpts -> Journal -> IO ()-balance opts@CliOpts{reportopts_=ropts} j = do-  d <- getCurrentDay-  case lineFormatFromOpts ropts of-    Left err -> error' $ unlines [err]-    Right _ -> do-      let format   = outputFormatFromOpts opts-          interval = interval_ ropts-      -- shenanigans: use single/multiBalanceReport when we must,-      -- ie when there's a report interval, or --historical or -- cumulative.-      -- Otherwise prefer the older balanceReport since it can elide boring parents.-      case interval of-        NoInterval -> do-          let report-                -- For --historical/--cumulative, we must use multiBalanceReport.-                -- (This forces --no-elide.)-                | balancetype_ ropts `elem` [HistoricalBalance, CumulativeChange]-                  = let ropts' | flat_ ropts = ropts-                               | otherwise   = ropts{accountlistmode_=ALTree}-                    in singleBalanceReport ropts' (queryFromOpts d ropts) j-                | otherwise = balanceReport ropts (queryFromOpts d ropts) j-              render = case format of-                "csv" -> \ropts r -> (++ "\n") $ printCSV $ balanceReportAsCsv ropts r-                _     -> balanceReportAsText-          writeOutput opts $ render ropts report-        _ -> do-          let report = multiBalanceReport ropts (queryFromOpts d ropts) j-              render = case format of-                "csv" -> \ropts r -> (++ "\n") $ printCSV $ multiBalanceReportAsCsv ropts r-                _     -> multiBalanceReportAsText-          writeOutput opts $ render ropts report---- single-column balance reports---- | Find the best commodity to convert to when asked to show the--- market value of this commodity on the given date. That is, the one--- in which it has most recently been market-priced, ie the commodity--- mentioned in the most recent applicable historical price directive--- before this date.--- defaultValuationCommodity :: Journal -> Day -> CommoditySymbol -> Maybe CommoditySymbol--- defaultValuationCommodity j d c = mpamount <$> commodityValue j d c---- | Render a single-column balance report as CSV.-balanceReportAsCsv :: ReportOpts -> BalanceReport -> CSV-balanceReportAsCsv opts (items, total) =-  ["account","balance"] :-  [[T.unpack a, showMixedAmountOneLineWithoutPrice b] | (a, _, _, b) <- items]-  ++-  if no_total_ opts-  then []-  else [["total", showMixedAmountOneLineWithoutPrice total]]---- | Render a single-column balance report as plain text.-balanceReportAsText :: ReportOpts -> BalanceReport -> String-balanceReportAsText opts ((items, total)) = unlines $ concat lines ++ t-  where-      fmt = lineFormatFromOpts opts-      lines = case fmt of-                Right fmt -> map (balanceReportItemAsText opts fmt) items-                Left err  -> [[err]]-      t = if no_total_ opts-           then []-           else-             case fmt of-               Right fmt ->-                let-                  -- abuse renderBalanceReportItem to render the total with similar format-                  acctcolwidth = maximum' [T.length fullname | (fullname, _, _, _) <- items]-                  totallines = map rstrip $ renderBalanceReportItem opts fmt (T.replicate (acctcolwidth+1) " ", 0, total)-                  -- with a custom format, extend the line to the full report width;-                  -- otherwise show the usual 20-char line for compatibility-                  overlinewidth | isJust (format_ opts) = maximum' $ map length $ concat lines-                                | otherwise             = defaultTotalFieldWidth-                  overline   = replicate overlinewidth '-'-                in overline : totallines-               Left _ -> []--tests_balanceReportAsText = [-  "balanceReportAsText" ~: do-  -- "unicode in balance layout" ~: do-    j <- readJournal'-      "2009/01/01 * медвежья шкура\n  расходы:покупки  100\n  актив:наличные\n"-    let opts = defreportopts-    balanceReportAsText opts (balanceReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is`-      unlines-      ["                -100  актив:наличные"-      ,"                 100  расходы:покупки"-      ,"--------------------"-      ,"                   0"-      ]- ]--{--:r-This implementation turned out to be a bit convoluted but implements the following algorithm for formatting:--- If there is a single amount, print it with the account name directly:-- Otherwise, only print the account name on the last line.--    a         USD 1   ; Account 'a' has a single amount-              EUR -1-    b         USD -1  ; Account 'b' has two amounts. The account name is printed on the last line.--}--- | Render one balance report line item as plain text suitable for console output (or--- whatever string format is specified). Note, prices will not be rendered, and--- differently-priced quantities of the same commodity will appear merged.--- The output will be one or more lines depending on the format and number of commodities.-balanceReportItemAsText :: ReportOpts -> StringFormat -> BalanceReportItem -> [String]-balanceReportItemAsText opts fmt (_, accountName, depth, amt) =-  renderBalanceReportItem opts fmt (-    maybeAccountNameDrop opts accountName,-    depth,-    normaliseMixedAmountSquashPricesForDisplay amt-    )---- | Render a balance report item using the given StringFormat, generating one or more lines of text.-renderBalanceReportItem :: ReportOpts -> StringFormat -> (AccountName, Int, MixedAmount) -> [String]-renderBalanceReportItem opts fmt (acctname, depth, total) =-  lines $-  case fmt of-    OneLine comps       -> concatOneLine      $ render1 comps-    TopAligned comps    -> concatBottomPadded $ render comps-    BottomAligned comps -> concatTopPadded    $ render comps-  where-    render1 = map (renderComponent1 opts (acctname, depth, total))-    render  = map (renderComponent opts (acctname, depth, total))--defaultTotalFieldWidth = 20---- | Render one StringFormat component for a balance report item.-renderComponent :: ReportOpts -> (AccountName, Int, MixedAmount) -> StringFormatComponent -> String-renderComponent _ _ (FormatLiteral s) = s-renderComponent opts (acctname, depth, total) (FormatField ljust min max field) = case field of-  DepthSpacerField -> formatString ljust Nothing max $ replicate d ' '-                      where d = case min of-                                 Just m  -> depth * m-                                 Nothing -> depth-  AccountField     -> formatString ljust min max (T.unpack acctname)-  TotalField       -> fitStringMulti min max True False $ showamt total-    where-      showamt | color_ opts = cshowMixedAmountWithoutPrice-              | otherwise   = showMixedAmountWithoutPrice-  _                -> ""---- | Render one StringFormat component for a balance report item.--- This variant is for use with OneLine string formats; it squashes--- any multi-line rendered values onto one line, comma-and-space separated,--- while still complying with the width spec.-renderComponent1 :: ReportOpts -> (AccountName, Int, MixedAmount) -> StringFormatComponent -> String-renderComponent1 _ _ (FormatLiteral s) = s-renderComponent1 opts (acctname, depth, total) (FormatField ljust min max field) = case field of-  AccountField     -> formatString ljust min max ((intercalate ", " . lines) (indented (T.unpack acctname)))-                      where-                        -- better to indent the account name here rather than use a DepthField component-                        -- so that it complies with width spec. Uses a fixed indent step size.-                        indented = ((replicate (depth*2) ' ')++)-  TotalField       -> fitStringMulti min max True False $ ((intercalate ", " . map strip . lines) (showamt total))-    where-      showamt | color_ opts = cshowMixedAmountWithoutPrice-              | otherwise   = showMixedAmountWithoutPrice -  _                -> ""---- multi-column balance reports---- | Render a multi-column balance report as CSV.-multiBalanceReportAsCsv :: ReportOpts -> MultiBalanceReport -> CSV-multiBalanceReportAsCsv opts (MultiBalanceReport (colspans, items, (coltotals,tot,avg))) =-  ("account" : "short account" : "indent" : map showDateSpan colspans-   ++ (if row_total_ opts then ["total"] else [])-   ++ (if average_ opts then ["average"] else [])-  ) :-  [T.unpack a : T.unpack a' : show i :-   map showMixedAmountOneLineWithoutPrice-   (amts-    ++ (if row_total_ opts then [rowtot] else [])-    ++ (if average_ opts then [rowavg] else []))-  | (a,a',i, amts, rowtot, rowavg) <- items]-  ++-  if no_total_ opts-  then []-  else [["totals", "", ""]-        ++ map showMixedAmountOneLineWithoutPrice (-           coltotals-           ++ (if row_total_ opts then [tot] else [])-           ++ (if average_ opts then [avg] else [])-           )]---- | Render a multi-column balance report as plain text suitable for console output.-multiBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> String-multiBalanceReportAsText opts r =-    printf "%s in %s:" typeStr (showDateSpan $ multiBalanceReportSpan r)-      ++ "\n"-      ++ renderBalanceReportTable opts tabl-  where-    tabl = balanceReportAsTable opts r-    typeStr :: String-    typeStr = case balancetype_ opts of-        PeriodChange -> "Balance changes"-        CumulativeChange -> "Ending balances (cumulative)"-        HistoricalBalance -> "Ending balances (historical)"---- | Given a table representing a multi-column balance report (for example,--- made using 'balanceReportAsTable'), render it in a format suitable for--- console output.-renderBalanceReportTable :: ReportOpts -> Table String String MixedAmount -> String-renderBalanceReportTable (ReportOpts { pretty_tables_ = pretty, color_=usecolor }) = unlines . trimborder . lines-                         . render pretty id (" " ++) showamt-                         . 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-    showamt | usecolor  = cshowMixedAmountOneLineWithoutPrice-            | otherwise = showMixedAmountOneLineWithoutPrice---- | Build a 'Table' from a multi-column balance report.-balanceReportAsTable :: ReportOpts -> MultiBalanceReport -> Table String String MixedAmount-balanceReportAsTable opts (MultiBalanceReport (colspans, items, (coltotals,tot,avg))) =-   addtotalrow $ Table-     (T.Group NoLine $ map Header accts)-     (T.Group NoLine $ map Header colheadings)-     (map rowvals items)-  where-    mkDate = case balancetype_ opts of-       PeriodChange -> showDateSpan-       _            -> maybe "" (showDate . prevday) . spanEnd-    colheadings = map mkDate colspans-                  ++ (if row_total_ opts then ["  Total"] else [])-                  ++ (if average_ opts then ["Average"] else [])-    accts = map renderacct items-    renderacct (a,a',i,_,_,_)-      | tree_ opts = replicate ((i-1)*2) ' ' ++ T.unpack a'-      | otherwise  = T.unpack $ maybeAccountNameDrop opts a-    rowvals (_,_,_,as,rowtot,rowavg) = as-                             ++ (if row_total_ opts then [rowtot] else [])-                             ++ (if average_ opts then [rowavg] else [])-    addtotalrow | no_total_ opts = id-                | otherwise      = (+----+ (row "" $-                                    coltotals-                                    ++ (if row_total_ opts && not (null coltotals) then [tot] else [])-                                    ++ (if average_ opts && not (null coltotals)   then [avg] else [])-                                    ))---- | 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)---tests_Hledger_Cli_Balance = TestList-  tests_balanceReportAsText
− Hledger/Cli/Balancesheet.hs
@@ -1,47 +0,0 @@-{-# LANGUAGE QuasiQuotes, RecordWildCards, NoCPP #-}-{-|--The @balancesheet@ command prints a simple balance sheet.---}--module Hledger.Cli.Balancesheet (-  balancesheetmode- ,balancesheet- ,tests_Hledger_Cli_Balancesheet-) where--import Data.String.Here-import System.Console.CmdArgs.Explicit-import Test.HUnit--import Hledger-import Hledger.Cli.CliOptions-import Hledger.Cli.CompoundBalanceCommand--balancesheetSpec = CompoundBalanceCommandSpec {-  cbcname     = "balancesheet",-  cbcaliases  = ["bs"],-  cbchelp     = [here|-This command displays a simple balance sheet, showing historical ending-balances of asset and liability accounts (ignoring any report begin date). -It assumes that these accounts are under a top-level `asset` or `liability`-account (case insensitive, plural forms also  allowed).-  |],-  cbctitle    = "Balance Sheet",-  cbcqueries  = [ ("Assets"     , journalAssetAccountQuery),-                 ("Liabilities", journalLiabilityAccountQuery)-               ],-  cbctype     = HistoricalBalance-}--balancesheetmode :: Mode RawOpts-balancesheetmode = compoundBalanceCommandMode balancesheetSpec--balancesheet :: CliOpts -> Journal -> IO ()-balancesheet = compoundBalanceCommand balancesheetSpec--tests_Hledger_Cli_Balancesheet :: Test-tests_Hledger_Cli_Balancesheet = TestList- [- ]
− Hledger/Cli/Cashflow.hs
@@ -1,48 +0,0 @@-{-# LANGUAGE QuasiQuotes, RecordWildCards, NoCPP #-}-{-|--The @cashflow@ command prints a simplified cashflow statement.  It just-shows the change in all "cash" accounts for the period (without the-traditional segmentation into operating, investing, and financing-cash flows.)---}--module Hledger.Cli.Cashflow (-  cashflowmode- ,cashflow- ,tests_Hledger_Cli_Cashflow-) where--import Data.String.Here-import System.Console.CmdArgs.Explicit-import Test.HUnit--import Hledger-import Hledger.Cli.CliOptions-import Hledger.Cli.CompoundBalanceCommand--cashflowSpec = CompoundBalanceCommandSpec {-  cbcname     = "cashflow",-  cbcaliases  = ["cf"],-  cbchelp     = [here|-This command displays a simple cashflow statement, showing changes-in "cash" accounts. It assumes that these accounts are under a top-level -`asset` account (case insensitive, plural forms also allowed) and do not -contain `receivable` or `A/R` in their name. -  |],-  cbctitle    = "Cashflow Statement",-  cbcqueries  = [("Cash flows", journalCashAccountQuery)],-  cbctype     = PeriodChange-}--cashflowmode :: Mode RawOpts-cashflowmode = compoundBalanceCommandMode cashflowSpec--cashflow :: CliOpts -> Journal -> IO ()-cashflow = compoundBalanceCommand cashflowSpec--tests_Hledger_Cli_Cashflow :: Test-tests_Hledger_Cli_Cashflow = TestList- [- ]
Hledger/Cli/CliOptions.hs view
@@ -15,6 +15,8 @@   inputflags,   reportflags,   outputflags,+  outputFormatFlag,+  outputFileFlag,   generalflagsgroup1,   generalflagsgroup2,   generalflagsgroup3,@@ -25,6 +27,8 @@   argsFlag,   showModeUsage,   withAliases,+  likelyExecutablesInPath,+  hledgerExecutablesInPath,    -- * CLI options   CliOpts(..),@@ -47,6 +51,7 @@   outputFormatFromOpts,   defaultWidth,   widthFromOpts,+  replaceNumericFlags,   -- | For register:   registerWidthsFromOpts,   maybeAccountNameDrop,@@ -58,8 +63,12 @@   topicForMode,    -- * Tests-  tests_Hledger_Cli_CliOptions+  tests_Hledger_Cli_CliOptions, +--  -- * Convenience re-exports+--  module Data.String.Here,+--  module System.Console.CmdArgs.Explicit,+--  module Test.HUnit ) where @@ -67,6 +76,7 @@ import Prelude.Compat import qualified Control.Exception as C import Control.Monad (when)+import Data.Char import Data.Default #if !MIN_VERSION_base(4,8,0) import Data.Functor.Compat ((<$>))@@ -76,6 +86,7 @@ import Data.List.Split (splitOneOf) import Data.Ord import Data.Maybe+--import Data.String.Here -- import Data.Text (Text) import qualified Data.Text as T import Safe@@ -102,10 +113,7 @@ -- | Common help flags: --help, --debug, --version... helpflags :: [Flag RawOpts] helpflags = [-  flagNone ["h"]    (setboolopt "h")    "show general usage (or after CMD, command usage)"- ,flagNone ["help"] (setboolopt "help") "show this program's manual as plain text (or after an addon CMD, the add-on's manual)"- ,flagNone ["man"]  (setboolopt "man")  "show this program's manual with man"- ,flagNone ["info"] (setboolopt "info") "show this program's manual with info"+  flagNone ["help","h"] (setboolopt "help") "show general usage (or after CMD, command usage)"  -- ,flagNone ["browse-args"] (setboolopt "browse-args") "use a web UI to select options and build up a command line"  ,flagReq  ["debug"]    (\s opts -> Right $ setopt "debug" s opts) "[N]" "show debug output (levels 1-9, default: 1)"  ,flagNone ["version"] (setboolopt "version") "show version information"@@ -137,23 +145,22 @@  ,flagNone ["quarterly","Q"] (setboolopt "quarterly") "multiperiod/multicolumn report by quarter"  ,flagNone ["yearly","Y"]    (setboolopt "yearly") "multiperiod/multicolumn report by year"  ,flagReq  ["period","p"]    (\s opts -> Right $ setopt "period" s opts) "PERIODEXP" "set start date, end date, and/or report interval all at once (overrides the flags above)"- ,flagNone ["date2"]         (setboolopt "date2") "show, and make -b/-e/-p/date: match, secondary dates instead"+ ,flagNone ["date2"]         (setboolopt "date2") "match the secondary date instead (see command help for other effects)"   ,flagNone ["unmarked","U"]  (setboolopt "unmarked") "include only unmarked postings/txns (can combine with -P or -C)"  ,flagNone ["pending","P"]   (setboolopt "pending") "include only pending postings/txns"  ,flagNone ["cleared","C"]   (setboolopt "cleared") "include only cleared postings/txns"  ,flagNone ["real","R"]      (setboolopt "real") "include only non-virtual postings"- ,flagReq  ["depth"]         (\s opts -> Right $ setopt "depth" s opts) "N" "hide accounts/postings deeper than N"+ ,flagReq  ["depth"]         (\s opts -> Right $ setopt "depth" s opts) "NUM" "(or -NUM): hide accounts/postings deeper than this"  ,flagNone ["empty","E"]     (setboolopt "empty") "show items with zero amount, normally hidden"  ,flagNone ["cost","B"]      (setboolopt "cost") "convert amounts to their cost at transaction time (using the transaction price, if any)"  ,flagNone ["value","V"]     (setboolopt "value") "convert amounts to their market value on the report end date (using the most recent applicable market price, if any)"  ]  -- | Common output-related flags: --output-file, --output-format...-outputflags = [-   flagReq  ["output-format","O"] (\s opts -> Right $ setopt "output-format" s opts) "FMT" "select the output format. Supported formats:\ntxt, csv."-  ,flagReq  ["output-file","o"]   (\s opts -> Right $ setopt "output-file" s opts) "FILE" "write output to FILE. A file extension matching one of the above formats selects that format."-  ]+outputflags = [outputFormatFlag, outputFileFlag]+outputFormatFlag = flagReq  ["output-format","O"] (\s opts -> Right $ setopt "output-format" s opts) "FMT" "select the output format. Supported formats:\ntxt, csv."+outputFileFlag   = flagReq  ["output-file","o"]   (\s opts -> Right $ setopt "output-file" s opts) "FILE" "write output to FILE. A file extension matching one of the above formats selects that format."  argsFlag :: FlagHelp -> Arg RawOpts argsFlag desc = flagArg (\s opts -> Right $ setopt "args" s opts) desc@@ -200,7 +207,7 @@   ,modeGroupFlags  = Group {      groupNamed   = []     ,groupUnnamed = [-       flagNone ["h"] (setboolopt "h") "Show usage."+       flagNone ["help"] (setboolopt "help") "Show usage."       -- ,flagNone ["help"] (setboolopt "help") "Show long help."       ]     ,groupHidden  = []             --  flags not displayed in the usage@@ -246,11 +253,10 @@         preamble = unlines $ reverse $ dropWhile null $ reverse preamblels         postamblelines = dropWhile null $ drop 1 postamblels --- | Build a cmdarg mode suitable for a hledger add-on command,+-- | Build a cmdarg mode for a hledger command, -- from a help template and flag/argument specifications. -- Reduces boilerplate a little, though the complicated cmdargs -- flag and argument specs are still required.--- See the addons in bin/ for examples of usage. hledgerCommandMode :: HelpTemplate -> [Flag RawOpts] -> [(Help, [Flag RawOpts])]    -> [Flag RawOpts] -> ([Arg RawOpts], Maybe (Arg RawOpts)) -> Mode RawOpts hledgerCommandMode tmpl ungroupedflags groupedflags hiddenflags args =@@ -336,11 +342,10 @@      rawopts_         :: RawOpts     ,command_         :: String     ,file_            :: [FilePath]-    ,rules_file_      :: Maybe FilePath+    ,inputopts_       :: InputOpts+    ,reportopts_      :: ReportOpts     ,output_file_     :: Maybe FilePath     ,output_format_   :: Maybe String-    ,alias_           :: [String]-    ,ignore_assertions_ :: Bool     ,debug_           :: Int            -- ^ debug level, set by @--debug[=N]@. See also 'Hledger.Utils.debugLevel'.     ,no_new_accounts_ :: Bool           -- add     ,width_           :: Maybe String   -- ^ the --width value provided, if any@@ -348,7 +353,6 @@                                         -- 1. the COLUMNS env var, if set                                         -- 2. the width reported by the terminal, if supported                                         -- 3. the default (80)-    ,reportopts_      :: ReportOpts  } deriving (Show, Data, Typeable)  instance Default CliOpts where def = defcliopts@@ -365,9 +369,7 @@     def     def     def-    def     defaultWidth-    def  -- | Convert possibly encoded option values to regular unicode strings. decodeRawOpts :: RawOpts -> RawOpts@@ -377,12 +379,21 @@ defaultWidth :: Int defaultWidth = 80 +-- | Replace any numeric flags (eg -2) with their long form (--depth 2),+-- as I'm guessing cmdargs doesn't support this directly.  +replaceNumericFlags :: [String] -> [String]+replaceNumericFlags = map replace+  where+    replace ('-':ds) | not (null ds) && all isDigit ds = "--depth="++ds+    replace s = s+ -- | Parse raw option string values to the desired final data types. -- Any relative smart dates will be converted to fixed dates based on -- today's date. Parsing failures will raise an error. -- Also records the terminal width, if supported. rawOptsToCliOpts :: RawOpts -> IO CliOpts rawOptsToCliOpts rawopts = checkCliOpts <$> do+  let iopts = rawOptsToInputOpts rawopts   ropts <- rawOptsToReportOpts rawopts   mcolumns <- readMay <$> getEnvSafe "COLUMNS"   mtermwidth <-@@ -397,16 +408,14 @@               rawopts_         = rawopts              ,command_         = stringopt "command" rawopts              ,file_            = map (T.unpack . stripquotes . T.pack) $ listofstringopt "file" rawopts-             ,rules_file_      = maybestringopt "rules-file" rawopts+             ,inputopts_       = iopts+             ,reportopts_      = ropts              ,output_file_     = maybestringopt "output-file" rawopts              ,output_format_   = maybestringopt "output-format" rawopts-             ,alias_           = map (T.unpack . stripquotes . T.pack) $ listofstringopt "alias" rawopts              ,debug_           = intopt "debug" rawopts-             ,ignore_assertions_ = boolopt "ignore-assertions" rawopts              ,no_new_accounts_ = boolopt "no-new-accounts" rawopts -- add              ,width_           = maybestringopt "width" rawopts              ,available_width_ = availablewidth-             ,reportopts_      = ropts              }  -- | Do final validation of processed opts, raising an error if there is trouble.@@ -424,6 +433,7 @@ -- and returns a CliOpts. Or, with --help or -h present, it prints  -- long or short help, and exits the program.  -- When --debug is present, also prints some debug output.+-- Note this is not used by the main hledger executable. -- -- The help texts are generated from the mode. -- Long help includes the full usage description generated by cmdargs@@ -443,12 +453,12 @@ -- getHledgerCliOpts :: Mode RawOpts -> IO CliOpts getHledgerCliOpts mode' = do-  args' <- getArgs+  args' <- getArgs >>= expandArgsAt   let rawopts = either usageError decodeRawOpts $ process mode' args'   opts <- rawOptsToCliOpts rawopts   debugArgs args' opts-  when ("help" `inRawOpts` rawopts_ opts) $ putStr longhelp  >> exitSuccess-  when ("h"    `inRawOpts` rawopts_ opts) $ putStr shorthelp >> exitSuccess+  when ("help" `inRawOpts` rawopts_ opts) $ putStr shorthelp >> exitSuccess+  -- when ("help" `inRawOpts` rawopts_ opts) $ putStr longhelp  >> exitSuccess   return opts   where     longhelp = showModeUsage mode'@@ -457,7 +467,7 @@         (reverse $ dropWhile null $ reverse $ takeWhile (not . ("flags:" `isInfixOf`)) $ lines longhelp)         ++         [""-        ,"  See --help for full detail, including common hledger options."+        ,"  See also hledger -h for general hledger options."         ]     -- | Print debug info about arguments and options if --debug is present.     debugArgs :: [String] -> CliOpts -> IO ()@@ -475,7 +485,7 @@ -- | Get the account name aliases from options, if any. aliasesFromOpts :: CliOpts -> [AccountAlias] aliasesFromOpts = map (\a -> fromparse $ runParser accountaliasp ("--alias "++quoteIfNeeded a) $ T.pack a)-                  . alias_+                  . aliases_ . inputopts_  -- | Get the (tilde-expanded, absolute) journal file path from -- 1. options, 2. an environment variable, or 3. the default.@@ -539,7 +549,7 @@ rulesFilePathFromOpts :: CliOpts -> IO (Maybe FilePath) rulesFilePathFromOpts opts = do   d <- getCurrentDirectory-  maybe (return Nothing) (fmap Just . expandPath d) $ rules_file_ opts+  maybe (return Nothing) (fmap Just . expandPath d) $ mrules_file_ $ inputopts_ opts  -- | Get the width in characters to use for console output. -- This comes from the --width option, or the COLUMNS environment@@ -636,23 +646,27 @@ compiledExts = ["",".com",".exe"]   --- | Get the sorted unique filenames of all hledger-* executables in--- the current user's PATH. Currently these are: files in any of the--- PATH directories, named hledger-*, with either no extension (and no--- periods in the name) or one of the addonExtensions.  Limitations:--- we do not currently check that the file is really a file (not eg a--- directory) or whether it has execute permission.-hledgerExecutablesInPath :: IO [String]-hledgerExecutablesInPath = do+-- | Get all sorted unique filenames in the current user's PATH. +-- We do not currently filter out non-file objects or files without execute permission.+likelyExecutablesInPath :: IO [String]+likelyExecutablesInPath = do   pathdirs <- splitOneOf "[:;]" `fmap` getEnvSafe "PATH"   pathfiles <- concat `fmap` mapM getDirectoryContentsSafe pathdirs-  return $ nub $ sort $ filter isHledgerExeName pathfiles-  -- XXX should exclude directories and files without execute permission.+  return $ nub $ sort pathfiles+  -- exclude directories and files without execute permission.   -- These will do a stat for each hledger-*, probably ok.   -- But they need paths, not just filenames-  -- hledgerexes  <- filterM doesFileExist hledgernamed-  -- hledgerexes' <- filterM isExecutable hledgerexes-  -- return hledgerexes+  -- exes'  <- filterM doesFileExist exe'+  -- exes'' <- filterM isExecutable exes'+  -- return exes''++-- | Get the sorted unique filenames of all hledger-* executables in+-- the current user's PATH. These are files in any of the PATH directories,+-- named hledger-*, with either no extension (and no periods in the name) +-- or one of the addonExtensions. +-- We do not currently filter out non-file objects or files without execute permission.+hledgerExecutablesInPath :: IO [String]+hledgerExecutablesInPath = filter isHledgerExeName <$> likelyExecutablesInPath  -- isExecutable f = getPermissions f >>= (return . executable) 
+ Hledger/Cli/Commands.hs view
@@ -0,0 +1,636 @@+{-|+hledger's built-in commands, and helpers for printing the commands list.+-}++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++module Hledger.Cli.Commands (+   findCommand+  ,builtinCommands+  ,builtinCommandNames+  ,printCommandsList+  ,tests_Hledger_Cli_Commands+  ,module Hledger.Cli.Commands.Accounts+  ,module Hledger.Cli.Commands.Activity+  ,module Hledger.Cli.Commands.Add+  ,module Hledger.Cli.Commands.Balance+  ,module Hledger.Cli.Commands.Balancesheet+  ,module Hledger.Cli.Commands.Balancesheetequity+  ,module Hledger.Cli.Commands.Cashflow+  ,module Hledger.Cli.Commands.Checkdates+  ,module Hledger.Cli.Commands.Checkdupes+  ,module Hledger.Cli.Commands.Equity+  ,module Hledger.Cli.Commands.Help+  ,module Hledger.Cli.Commands.Import+  ,module Hledger.Cli.Commands.Incomestatement+  ,module Hledger.Cli.Commands.Prices+  ,module Hledger.Cli.Commands.Print+  ,module Hledger.Cli.Commands.Printunique+  ,module Hledger.Cli.Commands.Register+  ,module Hledger.Cli.Commands.Registermatch+  ,module Hledger.Cli.Commands.Rewrite+  ,module Hledger.Cli.Commands.Stats+  ,module Hledger.Cli.Commands.Tags+) +where++import Control.Monad+import Data.List+import Data.List.Split (splitOn)+import Data.Monoid ((<>))+import Data.String.Here+import Data.Text (Text)+import qualified Data.Text as T+import Data.Time.Calendar+import System.Console.CmdArgs.Explicit as C+import System.Exit+import Test.HUnit++import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.Version+import Hledger.Cli.Commands.Accounts+import Hledger.Cli.Commands.Activity+import Hledger.Cli.Commands.Add+import Hledger.Cli.Commands.Balance+import Hledger.Cli.Commands.Balancesheet+import Hledger.Cli.Commands.Balancesheetequity+import Hledger.Cli.Commands.Cashflow+import Hledger.Cli.Commands.Checkdates+import Hledger.Cli.Commands.Checkdupes+import Hledger.Cli.Commands.Equity+import Hledger.Cli.Commands.Help+import Hledger.Cli.Commands.Import+import Hledger.Cli.Commands.Incomestatement+import Hledger.Cli.Commands.Prices+import Hledger.Cli.Commands.Print+import Hledger.Cli.Commands.Printunique+import Hledger.Cli.Commands.Register+import Hledger.Cli.Commands.Registermatch+import Hledger.Cli.Commands.Rewrite+import Hledger.Cli.Commands.Stats+import Hledger.Cli.Commands.Tags+++-- | The cmdargs subcommand mode and IO action for each builtin command.+-- Command actions take parsed CLI options and a (lazy) finalised journal.+builtinCommands :: [(Mode RawOpts, CliOpts -> Journal -> IO ())]+builtinCommands = [+   (accountsmode           , accounts)+  ,(activitymode           , activity)+  ,(addmode                , add)+  ,(balancemode            , balance)+  ,(balancesheetmode       , balancesheet)+  ,(balancesheetequitymode , balancesheetequity)+  ,(cashflowmode           , cashflow)+  ,(checkdatesmode         , checkdates)+  ,(checkdupesmode         , checkdupes)+  ,(equitymode             , equity)+  ,(helpmode               , help')+  ,(importmode             , importcmd)+  ,(incomestatementmode    , incomestatement)+  ,(pricesmode             , prices)+  ,(printmode              , print')+  ,(printuniquemode        , printunique)+  ,(registermode           , register)+  ,(registermatchmode      , registermatch)+  ,(rewritemode            , rewrite)+  ,(statsmode              , stats)+  ,(tagsmode               , tags)+  ,(testmode               , testcmd)+  ]++-- | All names and aliases of builtin commands.+builtinCommandNames :: [String]+builtinCommandNames = concatMap (modeNames . fst) builtinCommands++-- | Look up a builtin command's mode and action by exact command name or alias. +findCommand :: String -> Maybe (Mode RawOpts, CliOpts -> Journal -> IO ()) +findCommand cmdname = find (elem cmdname . modeNames . fst) builtinCommands ++-- | A template for the commands list, containing entries (indented lines)+-- for all known and some hypothetical builtin and addon commands.+-- These will be filtered based on the commands found at runtime,  +-- except those beginning with "hledger", which are not filtered. +-- PROGVERSION is replaced with the program name and version.+-- OTHER is replaced with an entry for each unknown addon command found. +--  +-- The command descriptions here should be kept synced with +-- each command's builtin help and with hledger manual's command list.+--+commandsList :: String+commandsList = [here|+-------------------------------------------------------------------------------+PROGVERSION, commands available:++Data entry:+ add                      add transactions using console ui+ iadd                     add transactions using curses ui+ import                   add new transactions from one or more import files+ edit                     open a text editor on some part of the journal++Statements:+ balancesheet (bs)        show a simple balance sheet with net worth+ balancesheetequity (bse) show a detailed balance sheet with equity+ cashflow (cf)            show a cashflow statement+ incomestatement (is)     show an income statement++Basic reports:+ accounts (a)             show account names+ activity                 show a chart of posting counts per interval+ aregister (ar, areg)     show transactions in a single account+ balance (b, bal)         show account balance changes or ending balances+ prices                   show market price records+ print (p, txns)          show transactions/journal entries+ register (r, reg)        show postings to one or more accounts+ stats                    show journal statistics+ tags                     show tag names++UIs:+ ui                       start curses ui+ web                      start web ui++Generating data:+ equity                   generate balance-resetting transactions+ interest                 generate interest transactions+ rewrite                  generate automated postings on matched transactions++Other/experimental:+ api                      start web api server+ autosync                 download/deduplicate/convert OFX data+ budget                   add automated postings/txns/bucket accts+ chart                    generate simple balance pie charts+ check                    check more powerful balance assertions+ check-dates              check transactions are ordered by date+ check-dupes              check for accounts with the same leaf name+ diff                     compare account transactions in two journal files+ irr                      calculate internal rate of return of an investment+ print-unique             show only transactions with unique descriptions+ register-match           show best matching transaction for a description+ test                     run self tests+OTHER+Help:+ help                     show any of the hledger manuals in various formats+ hledger CMD -h           show command usage+ hledger -h               show general usage+-------------------------------------------------------------------------------+|]++-- | Print the commands list, modifying the template above based on+-- the currently available addons. Missing addons will be removed, and+-- extra addons will be added under Misc.+printCommandsList :: [String] -> IO ()+printCommandsList addonsFound =+  putStr $+  regexReplace "PROGVERSION" (prognameandversion) $+  regexReplace "OTHER" (unlines $ map (' ':) unknownCommandsFound) $+  -- regexReplace "COUNT" (show cmdcount) $+  unlines $ concatMap adjustline $ lines $+  cmdlist+  where+    cmdlist = commandsList+    -- cmdcount = length $ commandsFromCommandsList cmdlist+    commandsFound = builtinCommandNames ++ addonsFound+    unknownCommandsFound = addonsFound \\ knownCommands++    adjustline l | " hledger " `isPrefixOf` l = [l]+    adjustline (' ':l) | not $ w `elem` commandsFound = []+      where w = takeWhile (not . (`elem` ['|',' '])) l+    adjustline l = [l]++knownCommands :: [String]+knownCommands = sort $ commandsFromCommandsList commandsList++-- | Extract the command names from a commands list like the above:+-- the first word (or words separated by |) of lines beginning with a space.+commandsFromCommandsList :: String -> [String]+commandsFromCommandsList s =+  concatMap (splitOn "|") [w | ' ':l <- lines s, let w:_ = words l]++++-- The test command, defined here so it can access other commands' tests.++testmode = (defCommandMode ["test"]) {+  modeHelp = "run built-in self-tests"+ ,modeArgs = ([], Just $ argsFlag "[REGEXPS]")+ ,modeGroupFlags = Group {+     groupUnnamed = []+    ,groupHidden = [+        flagNone ["tree"] (\opts -> setboolopt "tree" opts) "show tests hierarchically"+       ,flagNone ["flat"] (\opts -> setboolopt "flat" opts) "show tests as a flat list"+      ]+    ,groupNamed = [generalflagsgroup3]+    }+ }++-- | Run some or all hledger-lib and hledger unit tests, and exit with success or failure.+testcmd :: CliOpts -> Journal -> IO ()+testcmd opts _ = do+  let ts = +        (if tree_ $ reportopts_ opts then matchedTestsTree else matchedTestsFlat) +          opts tests_Hledger_Cli_Commands+  results <- liftM (fst . flip (,) 0) $ runTestTT ts+  if errors results > 0 || failures results > 0+    then exitFailure+    else exitWith ExitSuccess++-- | All or pattern-matched tests, as a flat list to show simple names.+matchedTestsFlat opts = TestList . +  filter (matchesAccount (queryFromOpts nulldate $ reportopts_ opts) . T.pack . testName) . +  flattenTests++-- | All or pattern-matched tests, in the original suites to show hierarchical names.+matchedTestsTree opts = +  filterTests (matchesAccount (queryFromOpts nulldate $ reportopts_ opts) . T.pack . testName) +++-- collected hledger-lib + hledger unit tests++tests_Hledger_Cli_Commands :: Test+tests_Hledger_Cli_Commands = TestList [+   tests_Hledger+  ,tests_Hledger_Cli_CliOptions+  -- ,tests_Hledger_Cli_Commands_Activity+  -- ,tests_Hledger_Cli_Commands_Add+  ,tests_Hledger_Cli_Commands_Balance+  ,tests_Hledger_Cli_Commands_Balancesheet+  ,tests_Hledger_Cli_Commands_Cashflow+  ,tests_Hledger_Cli_Commands_Incomestatement+  ,tests_Hledger_Cli_Commands_Print+  ,tests_Hledger_Cli_Commands_Register+  -- ,tests_Hledger_Cli_Commands_Stats++  -- some more tests easiest to define here:+  +  ,"apply account directive" ~: +    let ignoresourcepos j = j{jtxns=map (\t -> t{tsourcepos=nullsourcepos}) (jtxns j)} in+    let sameParse str1 str2 = do j1 <- readJournal Nothing Nothing True Nothing str1 >>= either error' (return . ignoresourcepos)+                                 j2 <- readJournal Nothing Nothing True Nothing str2 >>= either error' (return . ignoresourcepos)+                                 j1 `is` j2{jlastreadtime=jlastreadtime j1, jfiles=jfiles j1} --, jparsestate=jparsestate j1}+    in sameParse+                         ("2008/12/07 One\n  alpha  $-1\n  beta  $1\n" <>+                          "apply account outer\n2008/12/07 Two\n  aigh  $-2\n  bee  $2\n" <>+                          "apply account inner\n2008/12/07 Three\n  gamma  $-3\n  delta  $3\n" <>+                          "end apply account\n2008/12/07 Four\n  why  $-4\n  zed  $4\n" <>+                          "end apply account\n2008/12/07 Five\n  foo  $-5\n  bar  $5\n"+                         )+                         ("2008/12/07 One\n  alpha  $-1\n  beta  $1\n" <>+                          "2008/12/07 Two\n  outer:aigh  $-2\n  outer:bee  $2\n" <>+                          "2008/12/07 Three\n  outer:inner:gamma  $-3\n  outer:inner:delta  $3\n" <>+                          "2008/12/07 Four\n  outer:why  $-4\n  outer:zed  $4\n" <>+                          "2008/12/07 Five\n  foo  $-5\n  bar  $5\n"+                         )++  ,"apply account directive should preserve \"virtual\" posting type" ~: do+    j <- readJournal Nothing Nothing True Nothing "apply account test\n2008/12/07 One\n  (from)  $-1\n  (to)  $1\n" >>= either error' return+    let p = head $ tpostings $ head $ jtxns j+    assertBool "" $ paccount p == "test:from"+    assertBool "" $ ptype p == VirtualPosting+  +  ,"account aliases" ~: do+    j <- readJournal Nothing Nothing True Nothing "!alias expenses = equity:draw:personal\n1/1\n (expenses:food)  1\n" >>= either error' return+    let p = head $ tpostings $ head $ jtxns j+    assertBool "" $ paccount p == "equity:draw:personal:food"++  ,"ledgerAccountNames" ~:+    ledgerAccountNames ledger7 `is`+     ["assets","assets:cash","assets:checking","assets:saving","equity","equity:opening balances",+      "expenses","expenses:food","expenses:food:dining","expenses:phone","expenses:vacation",+      "liabilities","liabilities:credit cards","liabilities:credit cards:discover"]++  -- ,"journalCanonicaliseAmounts" ~:+  --  "use the greatest precision" ~:+  --   (map asprecision $ journalAmountAndPriceCommodities $ journalCanonicaliseAmounts $ journalWithAmounts ["1","2.00"]) `is` [2,2]++  -- don't know what this should do+  -- ,"elideAccountName" ~: do+  --    (elideAccountName 50 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa"+  --     `is` "aa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa")+  --    (elideAccountName 20 "aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa:aaaaaaaaaaaaaaaaaaaa"+  --     `is` "aa:aa:aaaaaaaaaaaaaa")++  ,"default year" ~: do+    j <- readJournal Nothing Nothing True Nothing defaultyear_journal_txt >>= either error' return+    tdate (head $ jtxns j) `is` fromGregorian 2009 1 1+    return ()++  ,"show dollars" ~: showAmount (usd 1) ~?= "$1.00"++  ,"show hours" ~: showAmount (hrs 1) ~?= "1.00h"++ ]+++-- test data++-- date1 = parsedate "2008/11/26"+-- t1 = LocalTime date1 midday++{-+samplejournal = readJournal' sample_journal_str++sample_journal_str = unlines+ ["; A sample journal file."+ ,";"+ ,"; Sets up this account tree:"+ ,"; assets"+ ,";   bank"+ ,";     checking"+ ,";     saving"+ ,";   cash"+ ,"; expenses"+ ,";   food"+ ,";   supplies"+ ,"; income"+ ,";   gifts"+ ,";   salary"+ ,"; liabilities"+ ,";   debts"+ ,""+ ,"2008/01/01 income"+ ,"    assets:bank:checking  $1"+ ,"    income:salary"+ ,""+ ,"2008/06/01 gift"+ ,"    assets:bank:checking  $1"+ ,"    income:gifts"+ ,""+ ,"2008/06/02 save"+ ,"    assets:bank:saving  $1"+ ,"    assets:bank:checking"+ ,""+ ,"2008/06/03 * eat & shop"+ ,"    expenses:food      $1"+ ,"    expenses:supplies  $1"+ ,"    assets:cash"+ ,""+ ,"2008/12/31 * pay off"+ ,"    liabilities:debts  $1"+ ,"    assets:bank:checking"+ ,""+ ,""+ ,";final comment"+ ]+-}++defaultyear_journal_txt :: Text+defaultyear_journal_txt = T.unlines+ ["Y2009"+ ,""+ ,"01/01 A"+ ,"    a  $1"+ ,"    b"+ ]++-- write_sample_journal = writeFile "sample.journal" sample_journal_str++-- entry2_str = unlines+--  ["2007/01/27 * joes diner"+--  ,"    expenses:food:dining                      $10.00"+--  ,"    expenses:gifts                            $10.00"+--  ,"    assets:checking                          $-20.00"+--  ,""+--  ]++-- entry3_str = unlines+--  ["2007/01/01 * opening balance"+--  ,"    assets:cash                                $4.82"+--  ,"    equity:opening balances"+--  ,""+--  ,"2007/01/01 * opening balance"+--  ,"    assets:cash                                $4.82"+--  ,"    equity:opening balances"+--  ,""+--  ,"2007/01/28 coopportunity"+--  ,"  expenses:food:groceries                 $47.18"+--  ,"  assets:checking"+--  ,""+--  ]++-- periodic_entry1_str = unlines+--  ["~ monthly from 2007/2/2"+--  ,"  assets:saving            $200.00"+--  ,"  assets:checking"+--  ,""+--  ]++-- periodic_entry2_str = unlines+--  ["~ monthly from 2007/2/2"+--  ,"  assets:saving            $200.00         ;auto savings"+--  ,"  assets:checking"+--  ,""+--  ]++-- periodic_entry3_str = unlines+--  ["~ monthly from 2007/01/01"+--  ,"    assets:cash                                $4.82"+--  ,"    equity:opening balances"+--  ,""+--  ,"~ monthly from 2007/01/01"+--  ,"    assets:cash                                $4.82"+--  ,"    equity:opening balances"+--  ,""+--  ]++-- journal1_str = unlines+--  [""+--  ,"2007/01/27 * joes diner"+--  ,"  expenses:food:dining                    $10.00"+--  ,"  expenses:gifts                          $10.00"+--  ,"  assets:checking                        $-20.00"+--  ,""+--  ,""+--  ,"2007/01/28 coopportunity"+--  ,"  expenses:food:groceries                 $47.18"+--  ,"  assets:checking                        $-47.18"+--  ,""+--  ,""+--  ]++-- journal2_str = unlines+--  [";comment"+--  ,"2007/01/27 * joes diner"+--  ,"  expenses:food:dining                    $10.00"+--  ,"  assets:checking                        $-47.18"+--  ,""+--  ]++-- journal3_str = unlines+--  ["2007/01/27 * joes diner"+--  ,"  expenses:food:dining                    $10.00"+--  ,";intra-entry comment"+--  ,"  assets:checking                        $-47.18"+--  ,""+--  ]++-- journal4_str = unlines+--  ["!include \"somefile\""+--  ,"2007/01/27 * joes diner"+--  ,"  expenses:food:dining                    $10.00"+--  ,"  assets:checking                        $-47.18"+--  ,""+--  ]++-- journal5_str = ""++-- journal6_str = unlines+--  ["~ monthly from 2007/1/21"+--  ,"    expenses:entertainment  $16.23        ;netflix"+--  ,"    assets:checking"+--  ,""+--  ,"; 2007/01/01 * opening balance"+--  ,";     assets:saving                            $200.04"+--  ,";     equity:opening balances                         "+--  ,""+--  ]++-- journal7_str = unlines+--  ["2007/01/01 * opening balance"+--  ,"    assets:cash                                $4.82"+--  ,"    equity:opening balances                         "+--  ,""+--  ,"2007/01/01 * opening balance"+--  ,"    income:interest                                $-4.82"+--  ,"    equity:opening balances                         "+--  ,""+--  ,"2007/01/02 * ayres suites"+--  ,"    expenses:vacation                        $179.92"+--  ,"    assets:checking                                 "+--  ,""+--  ,"2007/01/02 * auto transfer to savings"+--  ,"    assets:saving                            $200.00"+--  ,"    assets:checking                                 "+--  ,""+--  ,"2007/01/03 * poquito mas"+--  ,"    expenses:food:dining                       $4.82"+--  ,"    assets:cash                                     "+--  ,""+--  ,"2007/01/03 * verizon"+--  ,"    expenses:phone                            $95.11"+--  ,"    assets:checking                                 "+--  ,""+--  ,"2007/01/03 * discover"+--  ,"    liabilities:credit cards:discover         $80.00"+--  ,"    assets:checking                                 "+--  ,""+--  ,"2007/01/04 * blue cross"+--  ,"    expenses:health:insurance                 $90.00"+--  ,"    assets:checking                                 "+--  ,""+--  ,"2007/01/05 * village market liquor"+--  ,"    expenses:food:dining                       $6.48"+--  ,"    assets:checking                                 "+--  ,""+--  ]++journal7 :: Journal+journal7 = nulljournal {jtxns =+          [+           txnTieKnot Transaction {+             tindex=0,+             tsourcepos=nullsourcepos,+             tdate=parsedate "2007/01/01",+             tdate2=Nothing,+             tstatus=Unmarked,+             tcode="*",+             tdescription="opening balance",+             tcomment="",+             ttags=[],+             tpostings=+                 ["assets:cash" `post` usd 4.82+                 ,"equity:opening balances" `post` usd (-4.82)+                 ],+             tpreceding_comment_lines=""+           }+          ,+           txnTieKnot Transaction {+             tindex=0,+             tsourcepos=nullsourcepos,+             tdate=parsedate "2007/02/01",+             tdate2=Nothing,+             tstatus=Unmarked,+             tcode="*",+             tdescription="ayres suites",+             tcomment="",+             ttags=[],+             tpostings=+                 ["expenses:vacation" `post` usd 179.92+                 ,"assets:checking" `post` usd (-179.92)+                 ],+             tpreceding_comment_lines=""+           }+          ,+           txnTieKnot Transaction {+             tindex=0,+             tsourcepos=nullsourcepos,+             tdate=parsedate "2007/01/02",+             tdate2=Nothing,+             tstatus=Unmarked,+             tcode="*",+             tdescription="auto transfer to savings",+             tcomment="",+             ttags=[],+             tpostings=+                 ["assets:saving" `post` usd 200+                 ,"assets:checking" `post` usd (-200)+                 ],+             tpreceding_comment_lines=""+           }+          ,+           txnTieKnot Transaction {+             tindex=0,+             tsourcepos=nullsourcepos,+             tdate=parsedate "2007/01/03",+             tdate2=Nothing,+             tstatus=Unmarked,+             tcode="*",+             tdescription="poquito mas",+             tcomment="",+             ttags=[],+             tpostings=+                 ["expenses:food:dining" `post` usd 4.82+                 ,"assets:cash" `post` usd (-4.82)+                 ],+             tpreceding_comment_lines=""+           }+          ,+           txnTieKnot Transaction {+             tindex=0,+             tsourcepos=nullsourcepos,+             tdate=parsedate "2007/01/03",+             tdate2=Nothing,+             tstatus=Unmarked,+             tcode="*",+             tdescription="verizon",+             tcomment="",+             ttags=[],+             tpostings=+                 ["expenses:phone" `post` usd 95.11+                 ,"assets:checking" `post` usd (-95.11)+                 ],+             tpreceding_comment_lines=""+           }+          ,+           txnTieKnot Transaction {+             tindex=0,+             tsourcepos=nullsourcepos,+             tdate=parsedate "2007/01/03",+             tdate2=Nothing,+             tstatus=Unmarked,+             tcode="*",+             tdescription="discover",+             tcomment="",+             ttags=[],+             tpostings=+                 ["liabilities:credit cards:discover" `post` usd 80+                 ,"assets:checking" `post` usd (-80)+                 ],+             tpreceding_comment_lines=""+           }+          ]+         }++ledger7 :: Ledger+ledger7 = ledgerFromJournal Any journal7
+ Hledger/Cli/Commands/Accounts.hs view
@@ -0,0 +1,67 @@+{-|++The @accounts@ command lists account names:++- in flat mode (default), it lists the full names of accounts posted to by matched postings,+  clipped to the specified depth, possibly with leading components dropped.++- in tree mode, it shows the indented short names of accounts posted to by matched postings,+  and their parents, to the specified depth.++-}++{-# LANGUAGE OverloadedStrings #-}++module Hledger.Cli.Commands.Accounts (+  accountsmode+ ,accounts+ ,tests_Hledger_Cli_Commands_Accounts+) where++import Data.List+import Data.Monoid+-- import Data.Text (Text)+import qualified Data.Text as T+import System.Console.CmdArgs.Explicit as C+import Test.HUnit++import Hledger+import Prelude hiding (putStrLn)+import Hledger.Utils.UTF8IOCompat (putStrLn)+import Hledger.Cli.CliOptions+++-- | Command line options for this command.+accountsmode = (defCommandMode $ ["accounts"] ++ aliases) {+  modeHelp = "show account names" `withAliases` aliases+ ,modeHelpSuffix = [+    "This command lists the accounts referenced by matched postings (and in tree mode, their parents as well). The accounts can be depth-clipped (--depth N) or have their leading parts trimmed (--drop N)."+   ]+ ,modeGroupFlags = C.Group {+     groupUnnamed = [+      flagNone ["tree"] (\opts -> setboolopt "tree" opts) "show short account names, as a tree"+     ,flagNone ["flat"] (\opts -> setboolopt "flat" opts) "show full account names, as a list (default)"+     ,flagReq  ["drop"] (\s opts -> Right $ setopt "drop" s opts) "N" "flat mode: omit N leading account name parts"+     ]+    ,groupHidden = []+    ,groupNamed = [generalflagsgroup1]+    }+ }+  where aliases = ["a"]++-- | The accounts command.+accounts :: CliOpts -> Journal -> IO ()+accounts CliOpts{reportopts_=ropts} j = do+  d <- getCurrentDay+  let q = queryFromOpts d ropts+      nodepthq = dbg1 "nodepthq" $ filterQuery (not . queryIsDepth) q+      depth    = dbg1 "depth" $ queryDepth $ filterQuery queryIsDepth q+      ps = dbg1 "ps" $ journalPostings $ filterJournalPostings nodepthq j+      as = dbg1 "as" $ nub $ filter (not . T.null) $ map (clipAccountName depth) $ sort $ map paccount ps+      as' | tree_ ropts = expandAccountNames as+          | otherwise   = as+      render a | tree_ ropts = T.replicate (2 * (accountNameLevel a - 1)) " " <> accountLeafName a+               | otherwise   = maybeAccountNameDrop ropts a+  mapM_ (putStrLn . T.unpack . render) as'++tests_Hledger_Cli_Commands_Accounts = TestList []
+ Hledger/Cli/Commands/Activity.hs view
@@ -0,0 +1,58 @@+{-|++Print a bar chart of posting activity per day, or other report interval. ++-}++module Hledger.Cli.Commands.Activity+where++import Data.List+import Data.Maybe+import Data.Ord+import System.Console.CmdArgs.Explicit+import Text.Printf++import Hledger+import Hledger.Cli.CliOptions+import Prelude hiding (putStr)+import Hledger.Utils.UTF8IOCompat (putStr)++activitymode :: Mode RawOpts+activitymode = (defCommandMode $ ["activity"] ++ aliases) {+  modeHelp = "show an ascii barchart of posting counts per interval (default: daily)" `withAliases` aliases+ ,modeHelpSuffix = []+ ,modeGroupFlags = Group {+     groupUnnamed = []+    ,groupHidden = []+    ,groupNamed = [generalflagsgroup1]+    }+ }+  where aliases = []++barchar :: Char+barchar = '*'++-- | Print a bar chart of number of postings per report interval.+activity :: CliOpts -> Journal -> IO ()+activity CliOpts{reportopts_=ropts} j = do+  d <- getCurrentDay+  putStr $ showHistogram ropts (queryFromOpts d ropts) j++showHistogram :: ReportOpts -> Query -> Journal -> String+showHistogram opts q j = concatMap (printDayWith countBar) spanps+    where+      i = interval_ opts+      interval | i == NoInterval = Days 1+               | otherwise = i+      span' = queryDateSpan (date2_ opts) q `spanDefaultsFrom` journalDateSpan (date2_ opts) j+      spans = filter (DateSpan Nothing Nothing /=) $ splitSpan interval span'+      spanps = [(s, filter (isPostingInDateSpan s) ps) | s <- spans]+      -- same as Register+      -- should count transactions, not postings ?+      -- ps = sortBy (comparing postingDate) $ filterempties $ filter matchapats $ filterdepth $ journalPostings j+      ps = sortBy (comparing postingDate) $ filter (q `matchesPosting`) $ journalPostings j++printDayWith f (DateSpan b _, ps) = printf "%s %s\n" (show $ fromJust b) (f ps)++countBar ps = replicate (length ps) barchar
+ Hledger/Cli/Commands/Add.hs view
@@ -0,0 +1,455 @@+{-|+A history-aware add command to help with data entry.+|-}++{-# OPTIONS_GHC -fno-warn-missing-signatures -fno-warn-unused-do-bind #-}+{-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable, RecordWildCards, TypeOperators, FlexibleContexts, OverloadedStrings #-}++module Hledger.Cli.Commands.Add (+   addmode+  ,add+  ,appendToJournalFileOrStdout+  ,journalAddTransaction+  ,transactionsSimilarTo+)+where++import Prelude ()+import Prelude.Compat+import Control.Exception as E+import Control.Monad+import Control.Monad.Trans.Class+import Control.Monad.State.Strict (evalState, evalStateT)+import Control.Monad.Trans (liftIO)+import Data.Char (toUpper, toLower)+import Data.Functor.Identity (Identity(..))+import Data.List.Compat+import qualified Data.Set as S+import Data.Maybe+import Data.Text (Text)+import qualified Data.Text as T+import Data.Time.Calendar (Day)+import Data.Typeable (Typeable)+import Safe (headDef, headMay)+import System.Console.CmdArgs.Explicit+import System.Console.Haskeline (runInputT, defaultSettings, setComplete)+import System.Console.Haskeline.Completion+import System.Console.Wizard+import System.Console.Wizard.Haskeline+import System.IO ( stderr, hPutStr, hPutStrLn )+import Text.Megaparsec.Compat+import Text.Printf++import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.Commands.Register (postingsReportAsText)+++addmode = (defCommandMode ["add"]) {+  modeHelp = "prompt for transactions and add them to the journal"+ ,modeHelpSuffix = ["Defaults come from previous similar transactions; use query patterns to restrict these."]+ ,modeGroupFlags = Group {+     groupUnnamed = [+      flagNone ["no-new-accounts"]  (\opts -> setboolopt "no-new-accounts" opts) "don't allow creating new accounts"+     ]+    ,groupHidden = []+    ,groupNamed = [generalflagsgroup2]+    }+ }++-- | State used while entering transactions.+data EntryState = EntryState {+   esOpts               :: CliOpts           -- ^ command line options+  ,esArgs               :: [String]          -- ^ command line arguments remaining to be used as defaults+  ,esToday              :: Day               -- ^ today's date+  ,esDefDate            :: Day               -- ^ the default date for next transaction+  ,esJournal            :: Journal           -- ^ the journal we are adding to+  ,esSimilarTransaction :: Maybe Transaction -- ^ the most similar historical txn+  ,esPostings           :: [Posting]         -- ^ postings entered so far in the current txn+  } deriving (Show,Typeable)++defEntryState = EntryState {+   esOpts               = defcliopts+  ,esArgs               = []+  ,esToday              = nulldate+  ,esDefDate            = nulldate+  ,esJournal            = nulljournal+  ,esSimilarTransaction = Nothing+  ,esPostings           = []+}++data RestartTransactionException = RestartTransactionException deriving (Typeable,Show)+instance Exception RestartTransactionException++-- data ShowHelpException = ShowHelpException deriving (Typeable,Show)+-- instance Exception ShowHelpException++-- | Read multiple transactions from the console, prompting for each+-- field, and append them to the journal file.  If the journal came+-- from stdin, this command has no effect.+add :: CliOpts -> Journal -> IO ()+add opts j+    | journalFilePath j == "-" = return ()+    | otherwise = do+        hPrintf stderr "Adding transactions to journal file %s\n" (journalFilePath j)+        showHelp+        today <- getCurrentDay+        let es = defEntryState{esOpts=opts+                              ,esArgs=map (T.unpack . stripquotes . T.pack) $ listofstringopt "args" $ rawopts_ opts+                              ,esToday=today+                              ,esDefDate=today+                              ,esJournal=j+                              }+        getAndAddTransactions es `E.catch` (\(_::UnexpectedEOF) -> putStr "")++showHelp = hPutStr stderr $ unlines [+     "Any command line arguments will be used as defaults."+    ,"Use tab key to complete, readline keys to edit, enter to accept defaults."+    ,"An optional (CODE) may follow transaction dates."+    ,"An optional ; COMMENT may follow descriptions or amounts."+    ,"If you make a mistake, enter < at any prompt to restart the transaction."+    ,"To end a transaction, enter . when prompted."+    ,"To quit, enter . at a date prompt or press control-d or control-c."+    ]++-- | Loop reading transactions from the console, prompting, validating+-- and appending each one to the journal file, until end of input or+-- ctrl-c (then raise an EOF exception).  If provided, command-line+-- arguments are used as defaults; otherwise defaults come from the+-- most similar recent transaction in the journal.+getAndAddTransactions :: EntryState -> IO ()+getAndAddTransactions es@EntryState{..} = (do+  mt <- runInputT (setComplete noCompletion defaultSettings) (run $ haskeline $ confirmedTransactionWizard es)+  case mt of+    Nothing -> fail "urk ?"+    Just t -> do+      j <- if debug_ esOpts > 0+           then do hPrintf stderr "Skipping journal add due to debug mode.\n"+                   return esJournal+           else do j' <- journalAddTransaction esJournal esOpts t+                   hPrintf stderr "Saved.\n"+                   return j'+      hPrintf stderr "Starting the next transaction (. or ctrl-D/ctrl-C to quit)\n"+      getAndAddTransactions es{esJournal=j, esDefDate=tdate t}+  )+  `E.catch` (\(_::RestartTransactionException) ->+                 hPrintf stderr "Restarting this transaction.\n" >> getAndAddTransactions es)++-- confirmedTransactionWizard :: (ArbitraryIO :<: b, OutputLn :<: b, Line :<: b) => EntryState -> Wizard b Transaction+-- confirmedTransactionWizard :: EntryState -> Wizard Haskeline Transaction+confirmedTransactionWizard es@EntryState{..} = do+  t <- transactionWizard es+  -- liftIO $ hPrintf stderr {- "Transaction entered:\n%s" -} (show t)+  output $ show t+  y <- let def = "y" in+       retryMsg "Please enter y or n." $+        parser ((fmap ('y' ==)) . headMay . map toLower . strip) $+        defaultTo' def $ nonEmpty $+        maybeRestartTransaction $+        line $ green $ printf "Save this transaction to the journal ?%s: " (showDefault def)+  if y then return t else throw RestartTransactionException++transactionWizard es@EntryState{..} = do+  (date,code)    <- dateAndCodeWizard es+  let es1@EntryState{esArgs=args1} = es{esArgs=drop 1 esArgs, esDefDate=date}+  (desc,comment) <- descriptionAndCommentWizard es1+  let mbaset = similarTransaction es1 desc+  when (isJust mbaset) $ liftIO $ hPrintf stderr "Using this similar transaction for defaults:\n%s" (show $ fromJust mbaset)+  let es2 = es1{esArgs=drop 1 args1, esSimilarTransaction=mbaset}+      balancedPostingsWizard = do+        ps <- postingsWizard es2{esPostings=[]}+        let t = nulltransaction{tdate=date+                               ,tstatus=Unmarked+                               ,tcode=code+                               ,tdescription=desc+                               ,tcomment=comment+                               ,tpostings=ps+                               }+        case balanceTransaction Nothing t of -- imprecise balancing (?)+          Right t' -> return t'+          Left err -> liftIO (hPutStrLn stderr $ "\n" ++ (capitalize err) ++ "please re-enter.") >> balancedPostingsWizard+  balancedPostingsWizard++-- Identify the closest recent match for this description in past transactions.+similarTransaction :: EntryState -> Text -> Maybe Transaction+similarTransaction EntryState{..} desc =+  let q = queryFromOptsOnly esToday $ reportopts_ esOpts+      historymatches = transactionsSimilarTo esJournal q desc+      bestmatch | null historymatches = Nothing+                | otherwise           = Just $ snd $ head historymatches+  in bestmatch++dateAndCodeWizard EntryState{..} = do+  let def = headDef (showDate esDefDate) esArgs+  retryMsg "A valid hledger smart date is required. Eg: 2014/2/14, 14, yesterday." $+   parser (parseSmartDateAndCode esToday) $+   withCompletion (dateCompleter def) $+   defaultTo' def $ nonEmpty $+   maybeExit $+   maybeRestartTransaction $+   -- maybeShowHelp $+   line $ green $ printf "Date%s: " (showDefault def)+    where+      parseSmartDateAndCode refdate s = either (const Nothing) (\(d,c) -> return (fixSmartDate refdate d, c)) edc+          where+            edc = runParser (dateandcodep <* eof) "" $ T.pack $ lowercase s+            dateandcodep :: SimpleTextParser (SmartDate, Text)+            dateandcodep = do+                d <- smartdate+                c <- optional codep+                many spacenonewline+                eof+                return (d, T.pack $ fromMaybe "" c)+      -- defday = fixSmartDate today $ fromparse $ (parse smartdate "" . lowercase) defdate+      -- datestr = showDate $ fixSmartDate defday smtdate++descriptionAndCommentWizard EntryState{..} = do+  let def = headDef "" esArgs+  s <- withCompletion (descriptionCompleter esJournal def) $+       defaultTo' def $ nonEmpty $+       maybeRestartTransaction $+       line $ green $ printf "Description%s: " (showDefault def)+  let (desc,comment) = (T.pack $ strip a, T.pack $ strip $ dropWhile (==';') b) where (a,b) = break (==';') s+  return (desc, comment)++postingsWizard es@EntryState{..} = do+  mp <- postingWizard es+  case mp of Nothing -> return esPostings+             Just p  -> postingsWizard es{esArgs=drop 2 esArgs, esPostings=esPostings++[p]}++postingWizard es@EntryState{..} = do+  acct <- accountWizard es+  if acct `elem` [".",""]+  then case (esPostings, postingsBalanced esPostings) of+         ([],_)    -> liftIO (hPutStrLn stderr "Please enter some postings first.") >> postingWizard es+         (_,False) -> liftIO (hPutStrLn stderr "Please enter more postings to balance the transaction.") >> postingWizard es+         (_,True)  -> return Nothing -- no more postings, end of transaction+  else do+    let es1 = es{esArgs=drop 1 esArgs}+    (amt,comment)  <- amountAndCommentWizard es1+    return $ Just nullposting{paccount=T.pack $ stripbrackets acct+                             ,pamount=Mixed [amt]+                             ,pcomment=comment+                             ,ptype=accountNamePostingType $ T.pack acct+                             }++postingsBalanced :: [Posting] -> Bool+postingsBalanced ps = isRight $ balanceTransaction Nothing nulltransaction{tpostings=ps}++accountWizard EntryState{..} = do+  let pnum = length esPostings + 1+      historicalp = maybe Nothing (Just . (!! (pnum-1)) . (++ (repeat nullposting)) . tpostings) esSimilarTransaction+      historicalacct = case historicalp of Just p  -> showAccountName Nothing (ptype p) (paccount p)+                                           Nothing -> ""+      def = headDef historicalacct esArgs+      endmsg | canfinish && null def = " (or . or enter to finish this transaction)"+             | canfinish             = " (or . to finish this transaction)"+             | otherwise             = ""+  retryMsg "A valid hledger account name is required. Eg: assets:cash, expenses:food:eating out." $+   parser (parseAccountOrDotOrNull def canfinish) $+   withCompletion (accountCompleter esJournal def) $+   defaultTo' def $ -- nonEmpty $+   maybeRestartTransaction $+   line $ green $ printf "Account %d%s%s: " pnum (endmsg::String) (showDefault def)+    where+      canfinish = not (null esPostings) && postingsBalanced esPostings+      parseAccountOrDotOrNull :: String -> Bool -> String -> Maybe String+      parseAccountOrDotOrNull _  _ "."       = dbg1 $ Just "." -- . always signals end of txn+      parseAccountOrDotOrNull "" True ""     = dbg1 $ Just ""  -- when there's no default and txn is balanced, "" also signals end of txn+      parseAccountOrDotOrNull def@(_:_) _ "" = dbg1 $ Just def -- when there's a default, "" means use that+      parseAccountOrDotOrNull _ _ s          = dbg1 $ fmap T.unpack $+        either (const Nothing) validateAccount $+          flip evalState esJournal $ runParserT (accountnamep <* eof) "" (T.pack s) -- otherwise, try to parse the input as an accountname+        where+          validateAccount :: Text -> Maybe Text+          validateAccount t | no_new_accounts_ esOpts && not (t `elem` journalAccountNames esJournal) = Nothing+                            | otherwise = Just t+      dbg1 = id -- strace++amountAndCommentWizard EntryState{..} = do+  let pnum = length esPostings + 1+      (mhistoricalp,followedhistoricalsofar) =+          case esSimilarTransaction of+            Nothing                        -> (Nothing,False)+            Just Transaction{tpostings=ps} -> (if length ps >= pnum then Just (ps !! (pnum-1)) else Nothing+                                              ,all (\(a,b) -> pamount a == pamount b) $ zip esPostings ps)+      def = case (esArgs, mhistoricalp, followedhistoricalsofar) of+              (d:_,_,_)                                             -> d+              (_,Just hp,True)                                      -> showamt $ pamount hp+              _  | pnum > 1 && not (isZeroMixedAmount balancingamt) -> showamt balancingamtfirstcommodity+              _                                                     -> ""+  retryMsg "A valid hledger amount is required. Eg: 1, $2, 3 EUR, \"4 red apples\"." $+   parser parseAmountAndComment $+   withCompletion (amountCompleter def) $+   defaultTo' def $ nonEmpty $+   maybeRestartTransaction $+   line $ green $ printf "Amount  %d%s: " pnum (showDefault def)+    where+      parseAmountAndComment s = either (const Nothing) Just $+                                runParser+                                  (evalStateT (amountandcommentp <* eof) nodefcommodityj)+                                  ""+                                  (T.pack s)+      nodefcommodityj = esJournal{jparsedefaultcommodity=Nothing}+      amountandcommentp :: JournalParser Identity (Amount, Text)+      amountandcommentp = do+        a <- amountp+        lift (many spacenonewline)+        c <- T.pack <$> fromMaybe "" `fmap` optional (char ';' >> many anyChar)+        -- eof+        return (a,c)+      balancingamt = negate $ sum $ map pamount realps where realps = filter isReal esPostings+      balancingamtfirstcommodity = Mixed $ take 1 $ amounts balancingamt+      showamt =+        showMixedAmountWithPrecision+                  -- what should this be ?+                  -- 1 maxprecision (show all decimal places or none) ?+                  -- 2 maxprecisionwithpoint (show all decimal places or .0 - avoids some but not all confusion with thousands separators) ?+                  -- 3 canonical precision for this commodity in the journal ?+                  -- 4 maximum precision entered so far in this transaction ?+                  -- 5 3 or 4, whichever would show the most decimal places ?+                  -- I think 1 or 4, whichever would show the most decimal places+                  maxprecisionwithpoint+  --+  -- let -- (amt,comment) = (strip a, strip $ dropWhile (==';') b) where (a,b) = break (==';') amtcmt+      -- a           = fromparse $ runParser (amountp <|> return missingamt) (jparsestate esJournal) "" amt+  --     awithoutjps = fromparse $ runParser (amountp <|> return missingamt) mempty              "" amt+  --     defamtaccepted = Just (showAmount a) == mdefamt+  --     es2 = if defamtaccepted then es1 else es1{esHistoricalPostings=Nothing}+  --     mdefaultcommodityapplied = if acommodity a == acommodity awithoutjps then Nothing else Just $ acommodity a+  -- when (isJust mdefaultcommodityapplied) $+  --      liftIO $ hPutStrLn stderr $ printf "using default commodity (%s)" (fromJust mdefaultcommodityapplied)++maybeExit = parser (\s -> if s=="." then throw UnexpectedEOF else Just s)++maybeRestartTransaction = parser (\s -> if s=="<" then throw RestartTransactionException else Just s)++-- maybeShowHelp :: Wizard Haskeline String -> Wizard Haskeline String+-- maybeShowHelp wizard = maybe (liftIO showHelp >> wizard) return $+--                        parser (\s -> if s=="?" then Nothing else Just s) wizard++-- Completion helpers++dateCompleter :: String -> CompletionFunc IO+dateCompleter = completer ["today","tomorrow","yesterday"]++descriptionCompleter :: Journal -> String -> CompletionFunc IO+descriptionCompleter j = completer (map T.unpack $ journalDescriptions j)++accountCompleter :: Journal -> String -> CompletionFunc IO+accountCompleter j = completer (map T.unpack $ journalAccountNamesUsed j)++amountCompleter :: String -> CompletionFunc IO+amountCompleter = completer []++-- | Generate a haskeline completion function from the given+-- completions and default, that case insensitively completes with+-- prefix matches, or infix matches above a minimum length, or+-- completes the null string with the default.+completer :: [String] -> String -> CompletionFunc IO+completer completions def = completeWord Nothing "" completionsFor+    where+      simpleCompletion' s = (simpleCompletion s){isFinished=False}+      completionsFor "" = return [simpleCompletion' def]+      completionsFor i  = return (map simpleCompletion' ciprefixmatches)+          where+            ciprefixmatches = [c | c <- completions, i `isPrefixOf` c]+            -- mixed-case completions require haskeline > 0.7.1.2+            -- ciprefixmatches = [c | c <- completions, lowercase i `isPrefixOf` lowercase c]++--------------------------------------------------------------------------------++-- utilities++defaultTo' = flip defaultTo++withCompletion f = withSettings (setComplete f defaultSettings)++green s = "\ESC[1;32m\STX"++s++"\ESC[0m\STX"++showDefault "" = ""+showDefault s = " [" ++ s ++ "]"++-- | Append this transaction to the journal's file and transaction list.+journalAddTransaction :: Journal -> CliOpts -> Transaction -> IO Journal+journalAddTransaction j@Journal{jtxns=ts} opts t = do+  let f = journalFilePath j+  appendToJournalFileOrStdout f $ showTransactionUnelided t+    -- unelided shows all amounts explicitly, in case there's a price, cf #283+  when (debug_ opts > 0) $ do+    putStrLn $ printf "\nAdded transaction to %s:" f+    putStrLn =<< registerFromString (show t)+  return j{jtxns=ts++[t]}++-- | Append a string, typically one or more transactions, to a journal+-- file, or if the file is "-", dump it to stdout.  Tries to avoid+-- excess whitespace.+appendToJournalFileOrStdout :: FilePath -> String -> IO ()+appendToJournalFileOrStdout f s+  | f == "-"  = putStr s'+  | otherwise = appendFile f s'+  where s' = "\n" ++ ensureOneNewlineTerminated s++-- | Replace a string's 0 or more terminating newlines with exactly one.+ensureOneNewlineTerminated :: String -> String+ensureOneNewlineTerminated = (++"\n") . reverse . dropWhile (=='\n') . reverse++-- | Convert a string of journal data into a register report.+registerFromString :: String -> IO String+registerFromString s = do+  d <- getCurrentDay+  j <- readJournal' $ T.pack s+  return $ postingsReportAsText opts $ postingsReport ropts (queryFromOpts d ropts) j+      where+        ropts = defreportopts{empty_=True}+        opts = defcliopts{reportopts_=ropts}++capitalize :: String -> String+capitalize "" = ""+capitalize (c:cs) = toUpper c : cs++-- | Find the most similar and recent transactions matching the given+-- transaction description and report query.  Transactions are listed+-- with their "relevancy" score, most relevant first.+transactionsSimilarTo :: Journal -> Query -> Text -> [(Double,Transaction)]+transactionsSimilarTo j q desc =+    sortBy compareRelevanceAndRecency+               $ filter ((> threshold).fst)+               [(compareDescriptions desc $ tdescription t, t) | t <- ts]+    where+      compareRelevanceAndRecency (n1,t1) (n2,t2) = compare (n2,tdate t2) (n1,tdate t1)+      ts = filter (q `matchesTransaction`) $ jtxns j+      threshold = 0++-- | Return a similarity measure, from 0 to 1, for two transaction+-- descriptions.  This is like compareStrings, but first strips out+-- any numbers, to improve accuracy eg when there are bank transaction+-- ids from imported data.+compareDescriptions :: Text -> Text -> Double+compareDescriptions s t = compareStrings s' t'+    where s' = simplify $ T.unpack s+          t' = simplify $ T.unpack t+          simplify = filter (not . (`elem` ("0123456789" :: String)))++-- | Return a similarity measure, from 0 to 1, for two strings.  This+-- was based on Simon White's string similarity algorithm+-- (http://www.catalysoft.com/articles/StrikeAMatch.html), later found+-- to be https://en.wikipedia.org/wiki/S%C3%B8rensen%E2%80%93Dice_coefficient,+-- modified to handle short strings better.+-- Todo: check out http://nlp.fi.muni.cz/raslan/2008/raslan08.pdf#page=14 .+compareStrings :: String -> String -> Double+compareStrings "" "" = 1+compareStrings (_:[]) "" = 0+compareStrings "" (_:[]) = 0+compareStrings (a:[]) (b:[]) = if toUpper a == toUpper b then 1 else 0+compareStrings s1 s2 = 2 * commonpairs / totalpairs+    where+      pairs1      = S.fromList $ wordLetterPairs $ uppercase s1+      pairs2      = S.fromList $ wordLetterPairs $ uppercase s2+      commonpairs = fromIntegral $ S.size $ S.intersection pairs1 pairs2+      totalpairs  = fromIntegral $ S.size pairs1 + S.size pairs2++wordLetterPairs = concatMap letterPairs . words++letterPairs (a:b:rest) = [a,b] : letterPairs (b:rest)+letterPairs _ = []
+ Hledger/Cli/Commands/Balance.hs view
@@ -0,0 +1,553 @@+{-|++A ledger-compatible @balance@ command, with additional support for+multi-column reports.++Here is a description/specification for the balance command.  See also+"Hledger.Reports" -> \"Balance reports\".+++/Basic balance report/++With no report interval (@--monthly@ etc.), hledger's balance+command emulates ledger's, showing accounts indented according to+hierarchy, along with their total amount posted (including subaccounts).++Here's an example. With @examples/sample.journal@, which defines the following account tree:++@+ assets+   bank+     checking+     saving+   cash+ expenses+   food+   supplies+ income+   gifts+   salary+ liabilities+   debts+@++the basic @balance@ command gives this output:++@+ $ hledger -f sample.journal balance+                 $-1  assets+                  $1    bank:saving+                 $-2    cash+                  $2  expenses+                  $1    food+                  $1    supplies+                 $-2  income+                 $-1    gifts+                 $-1    salary+                  $1  liabilities:debts+--------------------+                   0+@++Subaccounts are displayed indented below their parent. Only the account leaf name (the final part) is shown.+(With @--flat@, account names are shown in full and unindented.)++Each account's \"balance\" is the sum of postings in that account and any subaccounts during the report period.+When the report period includes all transactions, this is equivalent to the account's current balance.++The overall total of the highest-level displayed accounts is shown below the line.+(The @--no-total/-N@ flag prevents this.)++/Eliding and omitting/++Accounts which have a zero balance, and no non-zero subaccount+balances, are normally omitted from the report.+(The @--empty/-E@ flag forces such accounts to be displayed.)+Eg, above @checking@ is omitted because it has a zero balance and no subaccounts.++Accounts which have a single subaccount also being displayed, with the same balance,+are normally elided into the subaccount's line.+(The @--no-elide@ flag prevents this.)+Eg, above @bank@ is elided to @bank:saving@ because it has only a+single displayed subaccount (@saving@) and their balance is the same+($1). Similarly, @liabilities@ is elided to @liabilities:debts@.++/Date limiting/++The default report period is that of the whole journal, including all+known transactions. The @--begin\/-b@, @--end\/-e@, @--period\/-p@+options or @date:@/@date2:@ patterns can be used to report only+on transactions before and/or after specified dates.++/Depth limiting/++The @--depth@ option can be used to limit the depth of the balance report.+Eg, to see just the top level accounts (still including their subaccount balances):++@+$ hledger -f sample.journal balance --depth 1+                 $-1  assets+                  $2  expenses+                 $-2  income+                  $1  liabilities+--------------------+                   0+@++/Account limiting/++With one or more account pattern arguments, the report is restricted+to accounts whose name matches one of the patterns, plus their parents+and subaccounts. Eg, adding the pattern @o@ to the first example gives:++@+ $ hledger -f sample.journal balance o+                  $1  expenses:food+                 $-2  income+                 $-1    gifts+                 $-1    salary+--------------------+                 $-1+@++* The @o@ pattern matched @food@ and @income@, so they are shown.++* @food@'s parent (@expenses@) is shown even though the pattern didn't+  match it, to clarify the hierarchy. The usual eliding rules cause it to be elided here.++* @income@'s subaccounts are also shown.++/Multi-column balance report/++hledger's balance command will show multiple columns when a reporting+interval is specified (eg with @--monthly@), one column for each sub-period.++There are three kinds of multi-column balance report, indicated by the heading:++* A \"period balance\" (or \"flow\") report (the default) shows the change of account+  balance in each period, which is equivalent to the sum of postings in each+  period. Here, checking's balance increased by 10 in Feb:++  > Change of balance (flow):+  >+  >                  Jan   Feb   Mar+  > assets:checking   20    10    -5++* A \"cumulative balance\" report (with @--cumulative@) shows the accumulated ending balance+  across periods, starting from zero at the report's start date.+  Here, 30 is the sum of checking postings during Jan and Feb:++  > Ending balance (cumulative):+  >+  >                  Jan   Feb   Mar+  > assets:checking   20    30    25++* A \"historical balance\" report (with @--historical/-H@) also shows ending balances,+  but it includes the starting balance from any postings before the report start date.+  Here, 130 is the balance from all checking postings at the end of Feb, including+  pre-Jan postings which created a starting balance of 100:++  > Ending balance (historical):+  >+  >                  Jan   Feb   Mar+  > assets:checking  120   130   125++/Eliding and omitting, 2/++Here's a (imperfect?) specification for the eliding/omitting behaviour:++* Each account is normally displayed on its own line.++* An account less deep than the report's max depth, with just one+interesting subaccount, and the same balance as the subaccount, is+non-interesting, and prefixed to the subaccount's line, unless+@--no-elide@ is in effect.++* An account with a zero inclusive balance and less than two interesting+subaccounts is not displayed at all, unless @--empty@ is in effect.++* Multi-column balance reports show full account names with no eliding+  (like @--flat@). Accounts (and periods) are omitted as described below.++/Which accounts to show in balance reports/++By default:++* single-column: accounts with non-zero balance in report period.+                 (With @--flat@: accounts with non-zero balance and postings.)++* periodic:      accounts with postings and non-zero period balance in any period++* cumulative:    accounts with non-zero cumulative balance in any period++* historical:    accounts with non-zero historical balance in any period++With @-E/--empty@:++* single-column: accounts with postings in report period++* periodic:      accounts with postings in report period++* cumulative:    accounts with postings in report period++* historical:    accounts with non-zero starting balance ++                 accounts with postings in report period++/Which periods (columns) to show in balance reports/++An empty period/column is one where no report account has any postings.+A zero period/column is one where no report account has a non-zero period balance.++Currently,++by default:++* single-column: N/A++* periodic:      all periods within the overall report period,+                 except for leading and trailing empty periods++* cumulative:    all periods within the overall report period,+                 except for leading and trailing empty periods++* historical:    all periods within the overall report period,+                 except for leading and trailing empty periods++With @-E/--empty@:++* single-column: N/A++* periodic:      all periods within the overall report period++* cumulative:    all periods within the overall report period++* historical:    all periods within the overall report period++/What to show in empty cells/++An empty periodic balance report cell is one which has no corresponding postings.+An empty cumulative/historical balance report cell is one which has no correponding+or prior postings, ie the account doesn't exist yet.+Currently, empty cells show 0.++-}++{-# LANGUAGE OverloadedStrings #-}++module Hledger.Cli.Commands.Balance (+  balancemode+ ,balance+ ,balanceReportAsText+ ,balanceReportItemAsText+ ,multiBalanceReportAsText+ ,multiBalanceReportAsCsv+ ,renderBalanceReportTable+ ,balanceReportAsTable+ ,tests_Hledger_Cli_Commands_Balance+) where++import Data.List (intercalate)+import Data.Maybe+-- import Data.Monoid+import qualified Data.Text as T+import System.Console.CmdArgs.Explicit as C+import Text.CSV+import Test.HUnit+import Text.Printf (printf)+import Text.Tabular as T+import Text.Tabular.AsciiWide++import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.Utils+++-- | Command line options for this command.+balancemode = (defCommandMode $ ["balance"] ++ aliases) { -- also accept but don't show the common bal alias+  modeHelp = "show accounts and balances" `withAliases` aliases+ ,modeGroupFlags = C.Group {+     groupUnnamed = [+      flagNone ["change"] (\opts -> setboolopt "change" opts)+        "show balance change in each period (default)"+     ,flagNone ["cumulative"] (\opts -> setboolopt "cumulative" opts)+        "show balance change accumulated across periods (in multicolumn reports)"+     ,flagNone ["historical","H"] (\opts -> setboolopt "historical" opts)+        "show historical ending balance in each period (includes postings before report start date)\n "+     ,flagNone ["tree"] (\opts -> setboolopt "tree" opts) "show accounts as a tree; amounts include subaccounts (default in simple reports)"+     ,flagNone ["flat"] (\opts -> setboolopt "flat" opts) "show accounts as a list; amounts exclude subaccounts except when account is depth-clipped (default in multicolumn reports)\n "+     ,flagNone ["average","A"] (\opts -> setboolopt "average" opts) "show a row average column (in multicolumn reports)"+     ,flagNone ["row-total","T"] (\opts -> setboolopt "row-total" opts) "show a row total column (in multicolumn reports)"+     ,flagNone ["no-total","N"] (\opts -> setboolopt "no-total" opts) "omit the final total row"+     ,flagReq  ["drop"] (\s opts -> Right $ setopt "drop" s opts) "N" "omit N leading account name parts (in flat mode)"+     ,flagNone ["no-elide"] (\opts -> setboolopt "no-elide" opts) "don't squash boring parent accounts (in tree mode)"+     ,flagReq  ["format"] (\s opts -> Right $ setopt "format" s opts) "FORMATSTR" "use this custom line format (in simple reports)"+     ,flagNone ["pretty-tables"] (\opts -> setboolopt "pretty-tables" opts) "use unicode when displaying tables"+     ,flagNone ["sort-amount","S"] (\opts -> setboolopt "sort-amount" opts) "sort by amount instead of account name"+     ]+     ++ outputflags+    ,groupHidden = []+    ,groupNamed = [generalflagsgroup1]+    }+ }+  where aliases = ["b","bal"]++-- | The balance command, prints a balance report.+balance :: CliOpts -> Journal -> IO ()+balance opts@CliOpts{reportopts_=ropts} j = do+  d <- getCurrentDay+  case lineFormatFromOpts ropts of+    Left err -> error' $ unlines [err]+    Right _ -> do+      let format   = outputFormatFromOpts opts+          interval = interval_ ropts+      -- XXX shenanigans: use singleBalanceReport or multiBalanceReport when we must, +      -- ie when there's a report interval, or when --historical or --cumulative +      -- are used (balanceReport doesn't handle those).+      -- Otherwise prefer the older balanceReport since it can elide boring parents.+      -- See also compoundBalanceCommandSingleColumnReport, singleBalanceReport etc.+      case interval of+        NoInterval -> do+          let report+                -- For --historical/--cumulative, we must use multiBalanceReport.+                -- (This forces --no-elide.)+                | balancetype_ ropts `elem` [HistoricalBalance, CumulativeChange]+                  = let ropts' | flat_ ropts = ropts+                               | otherwise   = ropts{accountlistmode_=ALTree}+                    in singleBalanceReport ropts' (queryFromOpts d ropts) j+                | otherwise = balanceReport ropts (queryFromOpts d ropts) j+              render = case format of+                "csv" -> \ropts r -> (++ "\n") $ printCSV $ balanceReportAsCsv ropts r+                _     -> balanceReportAsText+          writeOutput opts $ render ropts report+        _ -> do+          let report = multiBalanceReport ropts (queryFromOpts d ropts) j+              render = case format of+                "csv" -> \ropts r -> (++ "\n") $ printCSV $ multiBalanceReportAsCsv ropts r+                _     -> multiBalanceReportAsText+          writeOutput opts $ render ropts report++-- single-column balance reports++-- | Find the best commodity to convert to when asked to show the+-- market value of this commodity on the given date. That is, the one+-- in which it has most recently been market-priced, ie the commodity+-- mentioned in the most recent applicable historical price directive+-- before this date.+-- defaultValuationCommodity :: Journal -> Day -> CommoditySymbol -> Maybe CommoditySymbol+-- defaultValuationCommodity j d c = mpamount <$> commodityValue j d c++-- | Render a single-column balance report as CSV.+balanceReportAsCsv :: ReportOpts -> BalanceReport -> CSV+balanceReportAsCsv opts (items, total) =+  ["account","balance"] :+  [[T.unpack a, showMixedAmountOneLineWithoutPrice b] | (a, _, _, b) <- items]+  +++  if no_total_ opts+  then []+  else [["total", showMixedAmountOneLineWithoutPrice total]]++-- | Render a single-column balance report as plain text.+balanceReportAsText :: ReportOpts -> BalanceReport -> String+balanceReportAsText opts ((items, total)) = unlines $ concat lines ++ t+  where+      fmt = lineFormatFromOpts opts+      lines = case fmt of+                Right fmt -> map (balanceReportItemAsText opts fmt) items+                Left err  -> [[err]]+      t = if no_total_ opts+           then []+           else+             case fmt of+               Right fmt ->+                let+                  -- abuse renderBalanceReportItem to render the total with similar format+                  acctcolwidth = maximum' [T.length fullname | (fullname, _, _, _) <- items]+                  totallines = map rstrip $ renderBalanceReportItem opts fmt (T.replicate (acctcolwidth+1) " ", 0, total)+                  -- with a custom format, extend the line to the full report width;+                  -- otherwise show the usual 20-char line for compatibility+                  overlinewidth | isJust (format_ opts) = maximum' $ map length $ concat lines+                                | otherwise             = defaultTotalFieldWidth+                  overline   = replicate overlinewidth '-'+                in overline : totallines+               Left _ -> []++tests_balanceReportAsText = [+  "balanceReportAsText" ~: do+  -- "unicode in balance layout" ~: do+    j <- readJournal'+      "2009/01/01 * медвежья шкура\n  расходы:покупки  100\n  актив:наличные\n"+    let opts = defreportopts+    balanceReportAsText opts (balanceReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is`+      unlines+      ["                -100  актив:наличные"+      ,"                 100  расходы:покупки"+      ,"--------------------"+      ,"                   0"+      ]+ ]++{-+:r+This implementation turned out to be a bit convoluted but implements the following algorithm for formatting:++- If there is a single amount, print it with the account name directly:+- Otherwise, only print the account name on the last line.++    a         USD 1   ; Account 'a' has a single amount+              EUR -1+    b         USD -1  ; Account 'b' has two amounts. The account name is printed on the last line.+-}+-- | Render one balance report line item as plain text suitable for console output (or+-- whatever string format is specified). Note, prices will not be rendered, and+-- differently-priced quantities of the same commodity will appear merged.+-- The output will be one or more lines depending on the format and number of commodities.+balanceReportItemAsText :: ReportOpts -> StringFormat -> BalanceReportItem -> [String]+balanceReportItemAsText opts fmt (_, accountName, depth, amt) =+  renderBalanceReportItem opts fmt (+    maybeAccountNameDrop opts accountName,+    depth,+    normaliseMixedAmountSquashPricesForDisplay amt+    )++-- | Render a balance report item using the given StringFormat, generating one or more lines of text.+renderBalanceReportItem :: ReportOpts -> StringFormat -> (AccountName, Int, MixedAmount) -> [String]+renderBalanceReportItem opts fmt (acctname, depth, total) =+  lines $+  case fmt of+    OneLine comps       -> concatOneLine      $ render1 comps+    TopAligned comps    -> concatBottomPadded $ render comps+    BottomAligned comps -> concatTopPadded    $ render comps+  where+    render1 = map (renderComponent1 opts (acctname, depth, total))+    render  = map (renderComponent opts (acctname, depth, total))++defaultTotalFieldWidth = 20++-- | Render one StringFormat component for a balance report item.+renderComponent :: ReportOpts -> (AccountName, Int, MixedAmount) -> StringFormatComponent -> String+renderComponent _ _ (FormatLiteral s) = s+renderComponent opts (acctname, depth, total) (FormatField ljust min max field) = case field of+  DepthSpacerField -> formatString ljust Nothing max $ replicate d ' '+                      where d = case min of+                                 Just m  -> depth * m+                                 Nothing -> depth+  AccountField     -> formatString ljust min max (T.unpack acctname)+  TotalField       -> fitStringMulti min max True False $ showamt total+    where+      showamt | color_ opts = cshowMixedAmountWithoutPrice+              | otherwise   = showMixedAmountWithoutPrice+  _                -> ""++-- | Render one StringFormat component for a balance report item.+-- This variant is for use with OneLine string formats; it squashes+-- any multi-line rendered values onto one line, comma-and-space separated,+-- while still complying with the width spec.+renderComponent1 :: ReportOpts -> (AccountName, Int, MixedAmount) -> StringFormatComponent -> String+renderComponent1 _ _ (FormatLiteral s) = s+renderComponent1 opts (acctname, depth, total) (FormatField ljust min max field) = case field of+  AccountField     -> formatString ljust min max ((intercalate ", " . lines) (indented (T.unpack acctname)))+                      where+                        -- better to indent the account name here rather than use a DepthField component+                        -- so that it complies with width spec. Uses a fixed indent step size.+                        indented = ((replicate (depth*2) ' ')++)+  TotalField       -> fitStringMulti min max True False $ ((intercalate ", " . map strip . lines) (showamt total))+    where+      showamt | color_ opts = cshowMixedAmountWithoutPrice+              | otherwise   = showMixedAmountWithoutPrice +  _                -> ""++-- multi-column balance reports++-- | Render a multi-column balance report as CSV.+multiBalanceReportAsCsv :: ReportOpts -> MultiBalanceReport -> CSV+multiBalanceReportAsCsv opts (MultiBalanceReport (colspans, items, (coltotals,tot,avg))) =+  ("account" : "short account" : "indent" : map showDateSpan colspans+   ++ (if row_total_ opts then ["total"] else [])+   ++ (if average_ opts then ["average"] else [])+  ) :+  [T.unpack a : T.unpack a' : show i :+   map showMixedAmountOneLineWithoutPrice+   (amts+    ++ (if row_total_ opts then [rowtot] else [])+    ++ (if average_ opts then [rowavg] else []))+  | (a,a',i, amts, rowtot, rowavg) <- items]+  +++  if no_total_ opts+  then []+  else [["totals", "", ""]+        ++ map showMixedAmountOneLineWithoutPrice (+           coltotals+           ++ (if row_total_ opts then [tot] else [])+           ++ (if average_ opts then [avg] else [])+           )]++-- | Render a multi-column balance report as plain text suitable for console output.+multiBalanceReportAsText :: ReportOpts -> MultiBalanceReport -> String+multiBalanceReportAsText opts r =+    printf "%s in %s:\n\n" typeStr (showDateSpan $ multiBalanceReportSpan r)+      ++ renderBalanceReportTable opts tabl+  where+    tabl = balanceReportAsTable opts r+    typeStr :: String+    typeStr = case balancetype_ opts of+        PeriodChange -> "Balance changes"+        CumulativeChange -> "Ending balances (cumulative)"+        HistoricalBalance -> "Ending balances (historical)"++-- | Given a table representing a multi-column balance report (for example,+-- made using 'balanceReportAsTable'), render it in a format suitable for+-- console output.+renderBalanceReportTable :: ReportOpts -> Table String String MixedAmount -> String+renderBalanceReportTable (ReportOpts { pretty_tables_ = pretty, color_=usecolor }) = +  unlines+  . addtrailingblank+  . trimborder +  . lines+  . render pretty id id showamt+  . align+  where+    addtrailingblank = (++[""])+    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+    showamt | usecolor  = cshowMixedAmountOneLineWithoutPrice+            | otherwise = showMixedAmountOneLineWithoutPrice++-- | Build a 'Table' from a multi-column balance report.+balanceReportAsTable :: ReportOpts -> MultiBalanceReport -> Table String String MixedAmount+balanceReportAsTable opts (MultiBalanceReport (colspans, items, (coltotals,tot,avg))) =+   addtotalrow $ Table+     (T.Group NoLine $ map Header accts)+     (T.Group NoLine $ map Header colheadings)+     (map rowvals items)+  where+    mkDate = case balancetype_ opts of+       PeriodChange -> showDateSpan+       _            -> maybe "" (showDate . prevday) . spanEnd+    colheadings = map mkDate colspans+                  ++ (if row_total_ opts then ["  Total"] else [])+                  ++ (if average_ opts then ["Average"] else [])+    accts = map renderacct items+    renderacct (a,a',i,_,_,_)+      | tree_ opts = replicate ((i-1)*2) ' ' ++ T.unpack a'+      | otherwise  = T.unpack $ maybeAccountNameDrop opts a+    rowvals (_,_,_,as,rowtot,rowavg) = as+                             ++ (if row_total_ opts then [rowtot] else [])+                             ++ (if average_ opts then [rowavg] else [])+    addtotalrow | no_total_ opts = id+                | otherwise      = (+----+ (row "" $+                                    coltotals+                                    ++ (if row_total_ opts && not (null coltotals) then [tot] else [])+                                    ++ (if average_ opts && not (null coltotals)   then [avg] else [])+                                    ))++-- | 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)+++tests_Hledger_Cli_Commands_Balance = TestList+  tests_balanceReportAsText
+ Hledger/Cli/Commands/Balancesheet.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE QuasiQuotes, RecordWildCards, NoCPP #-}+{-|++The @balancesheet@ command prints a simple balance sheet.++-}++module Hledger.Cli.Commands.Balancesheet (+  balancesheetmode+ ,balancesheet+ ,tests_Hledger_Cli_Commands_Balancesheet+) where++import Data.String.Here+import System.Console.CmdArgs.Explicit+import Test.HUnit++import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.CompoundBalanceCommand++balancesheetSpec = CompoundBalanceCommandSpec {+  cbcname     = "balancesheet",+  cbcaliases  = ["bs"],+  cbchelp     = [here|+This command displays a simple balance sheet, showing historical ending+balances of asset and liability accounts (ignoring any report begin date). +It assumes that these accounts are under a top-level `asset` or `liability`+account (case insensitive, plural forms also  allowed).+  |],+  cbctitle    = "Balance Sheet",+  cbcqueries  = [ ("Assets"     , journalAssetAccountQuery,     Just NormalPositive),+                  ("Liabilities", journalLiabilityAccountQuery, Just NormalNegative)+                ],+  cbctype     = HistoricalBalance+}++balancesheetmode :: Mode RawOpts+balancesheetmode = compoundBalanceCommandMode balancesheetSpec++balancesheet :: CliOpts -> Journal -> IO ()+balancesheet = compoundBalanceCommand balancesheetSpec++tests_Hledger_Cli_Commands_Balancesheet :: Test+tests_Hledger_Cli_Commands_Balancesheet = TestList+ [+ ]
+ Hledger/Cli/Commands/Balancesheetequity.hs view
@@ -0,0 +1,40 @@+{-# LANGUAGE QuasiQuotes, RecordWildCards, NoCPP #-}+{-|++The @balancesheetequity@ command prints a simple balance sheet.++-}++module Hledger.Cli.Commands.Balancesheetequity (+  balancesheetequitymode+ ,balancesheetequity+) where++import Data.String.Here+import System.Console.CmdArgs.Explicit++import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.CompoundBalanceCommand++balancesheetequitySpec = CompoundBalanceCommandSpec {+  cbcname     = "balancesheetequity",+  cbcaliases  = ["bse"],+  cbchelp     = [here|This command displays a simple balance sheet, showing historical ending+balances of asset, liability and equity accounts (ignoring any report begin date). +It assumes that these accounts are under a top-level `asset`, `liability` and `equity`+account (plural forms also  allowed).+  |],+  cbctitle    = "Balance Sheet With Equity",+  cbcqueries  = [("Assets",      journalAssetAccountQuery,     Just NormalPositive),+                 ("Liabilities", journalLiabilityAccountQuery, Just NormalNegative),+                 ("Equity",      journalEquityAccountQuery,    Just NormalNegative)+              ],+  cbctype     = HistoricalBalance+}++balancesheetequitymode :: Mode RawOpts+balancesheetequitymode = compoundBalanceCommandMode balancesheetequitySpec++balancesheetequity :: CliOpts -> Journal -> IO ()+balancesheetequity = compoundBalanceCommand balancesheetequitySpec
+ Hledger/Cli/Commands/Cashflow.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE QuasiQuotes, RecordWildCards, NoCPP #-}+{-|++The @cashflow@ command prints a simplified cashflow statement.  It just+shows the change in all "cash" accounts for the period (without the+traditional segmentation into operating, investing, and financing+cash flows.)++-}++module Hledger.Cli.Commands.Cashflow (+  cashflowmode+ ,cashflow+ ,tests_Hledger_Cli_Commands_Cashflow+) where++import Data.String.Here+import System.Console.CmdArgs.Explicit+import Test.HUnit++import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.CompoundBalanceCommand++cashflowSpec = CompoundBalanceCommandSpec {+  cbcname     = "cashflow",+  cbcaliases  = ["cf"],+  cbchelp     = [here|+This command displays a simple cashflow statement, showing changes+in "cash" accounts. It assumes that these accounts are under a top-level +`asset` account (case insensitive, plural forms also allowed) and do not +contain `receivable` or `A/R` in their name. +  |],+  cbctitle    = "Cashflow Statement",+  cbcqueries  = [("Cash flows", journalCashAccountQuery, Just NormalPositive)],+  cbctype     = PeriodChange+}++cashflowmode :: Mode RawOpts+cashflowmode = compoundBalanceCommandMode cashflowSpec++cashflow :: CliOpts -> Journal -> IO ()+cashflow = compoundBalanceCommand cashflowSpec++tests_Hledger_Cli_Commands_Cashflow :: Test+tests_Hledger_Cli_Commands_Cashflow = TestList+ [+ ]
+ Hledger/Cli/Commands/Checkdates.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE QuasiQuotes #-}++module Hledger.Cli.Commands.Checkdates (+  checkdatesmode+ ,checkdates+ ,tests_Hledger_Cli_Commands_Checkdates+) where++import Data.String.Here+import Hledger+import Hledger.Cli.CliOptions+import System.Console.CmdArgs.Explicit+import Test.HUnit+import Text.Printf++-- checkdatesmode :: Mode RawOpts+checkdatesmode = hledgerCommandMode+  [here| check-dates+Check that transactions are sorted by increasing date.+With --date2, checks secondary dates instead.+With --strict, dates must also be unique.+With a query, only matched transactions' dates are checked.+Reads the default journal file, or another specified with -f.+FLAGS+  |]+  [flagNone ["strict"] (\opts -> setboolopt "strict" opts) "makes date comparing strict"]+  [generalflagsgroup1]+  []+  ([], Just $ argsFlag "[QUERY]")++checkdates :: CliOpts -> Journal -> IO ()+checkdates CliOpts{rawopts_=rawopts,reportopts_=ropts} j = do+  d <- getCurrentDay+  let ropts_ = ropts{accountlistmode_=ALFlat}+  let q = queryFromOpts d ropts_+  let ts = filter (q `matchesTransaction`) $+           jtxns $ journalSelectingAmountFromOpts ropts j+  let strict = boolopt "strict" rawopts+  let date = transactionDateFn ropts+  let compare a b =+        if strict+        then date a <  date b+        else date a <= date b+  case checkTransactions compare ts of+   FoldAcc{fa_previous=Nothing} -> putStrLn "ok (empty journal)"+   FoldAcc{fa_error=Nothing}    -> putStrLn "ok"+   FoldAcc{fa_error=Just error, fa_previous=Just previous} ->+    putStrLn $ printf ("ERROR: transaction out of%s date order"+     ++ "\nPrevious date: %s"+     ++ "\nDate: %s"+     ++ "\nLocation: %s"+     ++ "\nTransaction:\n\n%s")+     (if strict then " STRICT" else "")+     (show $ date previous)+     (show $ date error)+     (show $ tsourcepos error)+     (showTransactionUnelided error)++data FoldAcc a b = FoldAcc+ { fa_error    :: Maybe a+ , fa_previous :: Maybe b+ }++foldWhile :: (a -> FoldAcc a b -> FoldAcc a b) -> FoldAcc a b -> [a] -> FoldAcc a b+foldWhile _ acc [] = acc+foldWhile fold acc (a:as) =+  case fold a acc of+   acc@FoldAcc{fa_error=Just _} -> acc+   acc -> foldWhile fold acc as++checkTransactions :: (Transaction -> Transaction -> Bool)+ -> [Transaction] -> FoldAcc Transaction Transaction+checkTransactions compare ts =+  foldWhile fold FoldAcc{fa_error=Nothing, fa_previous=Nothing} ts+  where+    fold current acc@FoldAcc{fa_previous=Nothing} = acc{fa_previous=Just current}+    fold current acc@FoldAcc{fa_previous=Just previous} =+      if compare previous current+      then acc{fa_previous=Just current}+      else acc{fa_error=Just current}++tests_Hledger_Cli_Commands_Checkdates :: Test+tests_Hledger_Cli_Commands_Checkdates = TestList+ [+ ]
+ Hledger/Cli/Commands/Checkdupes.hs view
@@ -0,0 +1,49 @@+{-# LANGUAGE QuasiQuotes #-}++module Hledger.Cli.Commands.Checkdupes (+  checkdupesmode+ ,checkdupes+) +where++import Data.Function+import Data.List+import Data.String.Here+import qualified Data.Text as T+import Hledger+import Hledger.Cli.CliOptions+import System.Console.CmdArgs.Explicit+import Text.Printf++checkdupesmode :: Mode RawOpts+checkdupesmode = hledgerCommandMode+  [here| check-dupes+Reports account names having the same leaf but different prefixes. +In other words, two or more leaves that are categorized differently.+Reads the default journal file, or another specified as an argument.+An example: http://stefanorodighiero.net/software/hledger-dupes.html+  |]+  []+  [generalflagsgroup1]+  []+  ([], Nothing)++checkdupes _opts j = mapM_ render $ checkdupes' $ accountsNames j++accountsNames :: Journal -> [(String, AccountName)]+accountsNames j = map leafAndAccountName as+  where leafAndAccountName a = (T.unpack $ accountLeafName a, a)+        ps = journalPostings j+        as = nub $ sort $ map paccount ps++checkdupes' :: (Ord k, Eq k) => [(k, v)] -> [(k, [v])]+checkdupes' l = zip dupLeafs dupAccountNames+  where dupLeafs = map (fst . head) d+        dupAccountNames = map (map snd) d+        d = dupes' l+        dupes' = filter ((> 1) . length)+          . groupBy ((==) `on` fst)+          . sortBy (compare `on` fst)++render :: (String, [AccountName]) -> IO ()+render (leafName, accountNameL) = printf "%s as %s\n" leafName (concat $ intersperse ", " (map T.unpack accountNameL))
+ Hledger/Cli/Commands/Equity.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++module Hledger.Cli.Commands.Equity (+  equitymode+ ,equity+) +where++import Data.Maybe+import Data.String.Here+import Data.Time.Calendar+import Hledger+import Hledger.Cli.CliOptions++equitymode = hledgerCommandMode+  [here| equity+Print a "closing balances" transaction that brings all accounts (or with+query arguments, just the matched accounts) to a zero balance, followed by an+opposite "opening balances" transaction that restores the balances from zero.+Such transactions can be useful, eg, for bringing account balances across+file boundaries.++FLAGS++The opening balances transaction is useful to carry over+asset/liability balances if you choose to start a new journal file,+eg at the beginning of the year.++The closing balances transaction is useful to zero out balances in+the old file, which gives you the option of reporting on both files+at once while still seeing correct balances.++Balances are calculated, and the opening transaction is dated, as of+the report end date, which you should specify with -e or date: (and+the closing transaction is dated one day earlier). If a report end+date is not specified, it defaults to today.++Example:+```shell+$ hledger equity -f 2015.journal -e 2016/1/1 assets liabilities >>2015.journal+# move the opening balances transaction to 2016.journal+$ hledger -f 2015.journal bal assets liabilities not:desc:closing # shows correct 2015 balances+$ hledger -f 2016.journal bal assets liabilities                  # shows correct 2016 balances+$ hledger -f 2015.journal -f 2016.journal bal assets liabilities  # still shows correct 2016 balances+```+Open question: how to handle txns spanning a file boundary ? Eg:+```journal+2015/12/30 * food+    expenses:food:dining   $10+    assets:bank:checking  -$10  ; date:2016/1/4+```+This command might or might not have some connection to the concept of+"closing the books" in accounting.+  |]+  []+  [generalflagsgroup1]+  []+  ([], Just $ argsFlag "[QUERY]")++equity CliOpts{reportopts_=ropts} j = do+  today <- getCurrentDay+  let ropts_ = ropts{accountlistmode_=ALFlat}+      q = queryFromOpts today ropts_+      (acctbals,_) = balanceReport ropts_ q j+      balancingamt = negate $ sum $ map (\(_,_,_,b) -> normaliseMixedAmountSquashPricesForDisplay b) acctbals+      ps = [posting{paccount=a+                   ,pamount=mixed [b]+                   ,pbalanceassertion=Just b+                   }+           |(a,_,_,mb) <- acctbals+           ,b <- amounts $ normaliseMixedAmountSquashPricesForDisplay mb+           ]+           ++ [posting{paccount="equity:opening balances", pamount=balancingamt}]+      enddate = fromMaybe today $ queryEndDate (date2_ ropts_) q+      nps = [posting{paccount=a+                    ,pamount=mixed [negate b]+                    ,pbalanceassertion=Just b{aquantity=0}+                    }+            |(a,_,_,mb) <- acctbals+            ,b <- amounts $ normaliseMixedAmountSquashPricesForDisplay mb+            ]+           ++ [posting{paccount="equity:closing balances", pamount=negate balancingamt}]+  putStr $ showTransaction (nulltransaction{tdate=addDays (-1) enddate, tdescription="closing balances", tpostings=nps})+  putStr $ showTransaction (nulltransaction{tdate=enddate, tdescription="opening balances", tpostings=ps})
+ Hledger/Cli/Commands/Help.hs view
@@ -0,0 +1,84 @@+{-|++The help command.++|-}+--TODO rename manuals+--TODO substring matching++{-# LANGUAGE QuasiQuotes #-}++module Hledger.Cli.Commands.Help (++   helpmode+  ,help'++  ) where++import Prelude ()+import Prelude.Compat+import Data.Char+import Data.List+import Data.Maybe+import Data.String.Here+import Safe+import System.Console.CmdArgs.Explicit+import System.Environment+import System.IO++import Hledger.Data.RawOptions+import Hledger.Data.Types+import Hledger.Cli.CliOptions+import Hledger.Cli.DocFiles+--import Hledger.Utils.Debug++helpmode = (defCommandMode $ ["help"] ++ aliases) {+  modeHelp = "show any of the hledger manuals, choosing the most suitable viewer (info, man, a pager, or stdout). With no argument, list the manuals." `withAliases` aliases+ ,modeGroupFlags = Group {+     groupUnnamed = [+      flagNone ["info"]  (setboolopt "info")  "show the manual with info"+     ,flagNone ["man"]   (setboolopt "man")   "show the manual with man"+     ,flagNone ["pager"] (setboolopt "pager") "show the manual with $PAGER or less"+     ,flagNone ["cat"]   (setboolopt "cat")   "show the manual on stdout"+     ,flagNone ["help","h"]  (setboolopt "help")  "show this help"+     ]+    ,groupHidden = []+    ,groupNamed = []+    }+ ,modeArgs = ([], Just $ argsFlag "[MANUAL]")+}+  where aliases = []++-- | List or display one of the hledger manuals in various formats. +-- You can select a docs viewer with one of the `--info`, `--man`, `--pager`, `--cat` flags.+-- Otherwise it will use the first available of: info, man, $PAGER, less, stdout+-- (and always stdout if output is non-interactive). +help' :: CliOpts -> Journal -> IO ()+help' opts _ = do+  exes <- likelyExecutablesInPath+  pagerprog <- fromMaybe "less" <$> lookupEnv "PAGER"+  interactive <- hIsTerminalDevice stdout+  let+    args = take 1 $ listofstringopt "args" $ rawopts_ opts+    topic = case args of+              [pat] -> headMay [t | t <- docTopics, map toLower pat `isInfixOf` t]+              _   -> Nothing+    [info, man, pager, cat] = +      [runInfoForTopic, runManForTopic, runPagerForTopic pagerprog, printHelpForTopic]+    viewer+      | boolopt "info"  $ rawopts_ opts = info+      | boolopt "man"   $ rawopts_ opts = man+      | boolopt "pager" $ rawopts_ opts = pager+      | boolopt "cat"   $ rawopts_ opts = cat+      | not interactive                 = cat +      | "info"    `elem` exes           = info+      | "man"     `elem` exes           = man+      | pagerprog `elem` exes           = pager+      | otherwise                       = cat +  case topic of+    Nothing -> putStrLn $ [here|+Please choose a manual by typing "hledger help MANUAL" (any substring is ok).+A viewer (info, man, a pager, or stdout) will be auto-selected,+or type "hledger help -h" to see options. Manuals available:+|] ++ "\n " ++ intercalate " " docTopics+    Just t  -> viewer t
+ Hledger/Cli/Commands/Import.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++module Hledger.Cli.Commands.Import (+  importmode+ ,importcmd+) +where++import Control.Monad+import Data.List+import Data.Ord+import Data.String.Here+import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.Commands.Add (journalAddTransaction)+-- import Hledger.Cli.Commands.Print (print')+import System.Console.CmdArgs.Explicit+import Text.Printf++importmode = hledgerCommandMode+  [here| import+Read new transactions added to each FILE since last run, and add them to+the main journal file. Or with --dry-run, just print the transactions +that would be added.++Input files are provided as arguments, or glob patterns. So eg to add new +transactions from all CSV files to the main journal: hledger import *.csv++New transactions are detected like print --new (using .latest.FILE state files)++FLAGS+  |]+  [flagNone ["dry-run"] (\opts -> setboolopt "dry-run" opts) "just show the transactions to be imported"] +  [generalflagsgroup1]+  []+  ([], Just $ argsFlag "FILE [...]")++importcmd opts@CliOpts{rawopts_=rawopts,inputopts_=iopts} j = do+  let+    inputfiles = listofstringopt "args" rawopts+    dryrun = boolopt "dry-run" rawopts+    iopts' = iopts{new_=True, new_save_=not dryrun}+  case inputfiles of+    [] -> error' "please provide one or more input files as arguments"+    fs -> do+      enewj <- readJournalFilesWithOpts iopts' fs+      case enewj of+        Left e     -> error' e +        Right newj ->+          case sortBy (comparing tdate) $ jtxns newj of+            [] -> putStrLn "no new transactions"+            newts | dryrun -> do+              printf "would import %d new transactions:\n\n" (length newts)+              -- TODO how to force output here ?+              -- length (jtxns newj) `seq` print' opts{rawopts_=("explicit",""):rawopts} newj+              mapM_ (putStr . showTransactionUnelided) newts+            newts -> do+              foldM (flip journalAddTransaction opts) j newts  -- gets forced somehow.. (how ?)+              printf "imported %d new transactions\n" (length newts)
+ Hledger/Cli/Commands/Incomestatement.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE QuasiQuotes, TemplateHaskell, OverloadedStrings, NoCPP #-}+{-|++The @incomestatement@ command prints a simple income statement (profit & loss report).++-}++module Hledger.Cli.Commands.Incomestatement (+  incomestatementmode+ ,incomestatement+ ,tests_Hledger_Cli_Commands_Incomestatement+) where++import Data.String.Here+import System.Console.CmdArgs.Explicit+import Test.HUnit++import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.CompoundBalanceCommand++incomestatementSpec = CompoundBalanceCommandSpec {+  cbcname     = "incomestatement",+  cbcaliases  = ["is"],+  cbchelp     = [here|+This command displays a simple income statement, showing revenues+and expenses during a period. It assumes that these accounts are under a +top-level `revenue` or `income` or `expense` account (case insensitive,+plural forms also allowed).+  |],+  cbctitle    = "Income Statement",+  cbcqueries  = [ ("Revenues", journalIncomeAccountQuery, Just NormalNegative),+                  ("Expenses", journalExpenseAccountQuery, Just NormalPositive)+                ],+  cbctype     = PeriodChange+}++incomestatementmode :: Mode RawOpts+incomestatementmode = compoundBalanceCommandMode incomestatementSpec++incomestatement :: CliOpts -> Journal -> IO ()+incomestatement = compoundBalanceCommand incomestatementSpec++tests_Hledger_Cli_Commands_Incomestatement :: Test+tests_Hledger_Cli_Commands_Incomestatement = TestList+ [+ ]
+ Hledger/Cli/Commands/Prices.hs view
@@ -0,0 +1,84 @@+{-# LANGUAGE QuasiQuotes #-}++module Hledger.Cli.Commands.Prices (+  pricesmode+ ,prices+) +where++import Data.Maybe+import Data.List+import Data.String.Here+import qualified Data.Text as T+import Data.Time+import Hledger+import Hledger.Cli.CliOptions+import System.Console.CmdArgs.Explicit++pricesmode = hledgerCommandMode+  [here| prices+Print all market prices from the journal.+  |]+  [flagNone ["costs"] (setboolopt "costs") "print transaction prices from postings"+  ,flagNone ["inverted-costs"] (setboolopt "inverted-costs") "print transaction inverted prices from postings also"]+  [generalflagsgroup1]+  []+  ([], Nothing)++prices opts j = do+  -- XXX the original hledger-prices script always ignored assertions +  let cprices = concatMap postingCosts . allPostings $ j+      icprices = concatMap postingCosts . mapAmount invertPrice . allPostings $ j+      printPrices = mapM_ (putStrLn . showPrice)+      forBoolOpt opt | boolopt opt $ rawopts_ opts = id+                     | otherwise = const []+      allPrices = sortOn mpdate . concat $+          [ jmarketprices j+          , forBoolOpt "costs" cprices+          , forBoolOpt "inverted-costs" icprices+          ]+  +  printPrices allPrices++showPrice :: MarketPrice -> String+showPrice mp = unwords ["P", show $ mpdate mp, T.unpack . quoteCommoditySymbolIfNeeded $ mpcommodity mp, showAmountWithZeroCommodity $ mpamount mp]++divideAmount' :: Amount -> Quantity -> Amount+divideAmount' a d = a' where+    a' = (a `divideAmount` d) { astyle = style' }+    style' = (astyle a) { asprecision = precision' }+    extPrecision = (1+) . floor . logBase 10 $ (realToFrac d :: Double)+    precision' = extPrecision + asprecision (astyle a)++invertPrice :: Amount -> Amount+invertPrice a =+    case aprice a of+        NoPrice -> a+        UnitPrice pa -> invertPrice+            -- normalize to TotalPrice+            a { aprice = TotalPrice pa' } where+                pa' = (pa `divideAmount` (1 / aquantity a)) { aprice = NoPrice }+        TotalPrice pa ->+            a { aquantity = aquantity pa * signum (aquantity a), acommodity = acommodity pa, aprice = TotalPrice pa' } where+                pa' = pa { aquantity = abs $ aquantity a, acommodity = acommodity a, aprice = NoPrice, astyle = astyle a }++amountCost :: Day -> Amount -> Maybe MarketPrice+amountCost d a =+    case aprice a of+        NoPrice -> Nothing+        UnitPrice pa -> Just+            MarketPrice { mpdate = d, mpcommodity = acommodity a, mpamount = pa }+        TotalPrice pa -> Just+            MarketPrice { mpdate = d, mpcommodity = acommodity a, mpamount = pa `divideAmount'` abs (aquantity a) }++postingCosts :: Posting -> [MarketPrice]+postingCosts p = mapMaybe (amountCost date) . amounts $ pamount p  where+   date = fromMaybe (tdate . fromJust $ ptransaction p) $ pdate p++allPostings :: Journal -> [Posting]+allPostings = concatMap tpostings . jtxns++mapAmount :: (Amount -> Amount) -> [Posting] -> [Posting]+mapAmount f = map pf where+    pf p = p { pamount = mf (pamount p) }+    mf = mixed . map f . amounts
+ Hledger/Cli/Commands/Print.hs view
@@ -0,0 +1,180 @@+{-|++A ledger-compatible @print@ command.++-}++{-# LANGUAGE OverloadedStrings #-}++module Hledger.Cli.Commands.Print (+  printmode+ ,print'+ -- ,entriesReportAsText+ ,originalTransaction+ ,tests_Hledger_Cli_Commands_Print+)+where++import Data.Text (Text)+import qualified Data.Text as T+import System.Console.CmdArgs.Explicit+import Test.HUnit+import Text.CSV++import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.Utils+import Hledger.Cli.Commands.Add ( transactionsSimilarTo )+++printmode = (defCommandMode $ ["print"] ++ aliases) {+  modeHelp = "show transaction journal entries, sorted by date. With --date2, sort by secondary date instead." `withAliases` aliases+ ,modeGroupFlags = Group {+     groupUnnamed = [+         let arg = "STR" in+         flagReq  ["match","m"] (\s opts -> Right $ setopt "match" s opts) arg+          ("show the transaction whose description is most similar to "++arg++", and is most recent")+        ,flagNone ["explicit","x"] (setboolopt "explicit")+          "show all amounts explicitly"+        ,flagNone ["new"] (setboolopt "new")+          "show only newer-dated transactions added in each file since last run"+        ]+        ++ outputflags+    ,groupHidden = []+    ,groupNamed = [generalflagsgroup1]+    }+ }+  where aliases = ["p","txns"]++-- | Print journal transactions in standard format.+print' :: CliOpts -> Journal -> IO ()+print' opts j = do+  case maybestringopt "match" $ rawopts_ opts of+    Nothing   -> printEntries opts j+    Just desc -> printMatch opts j $ T.pack desc++printEntries :: CliOpts -> Journal -> IO ()+printEntries opts@CliOpts{reportopts_=ropts} j = do+  d <- getCurrentDay+  let q = queryFromOpts d ropts+      fmt = outputFormatFromOpts opts+      (render, ropts') = case fmt of+        "csv" -> ((++"\n") . printCSV . entriesReportAsCsv, ropts{accountlistmode_=ALFlat})+        _     -> (entriesReportAsText opts,                 ropts)+  writeOutput opts $ render $ entriesReport ropts' q j++entriesReportAsText :: CliOpts -> EntriesReport -> String+entriesReportAsText opts = concatMap (showTransactionUnelided . gettxn) +  where+    gettxn | boolopt "explicit" $ rawopts_ opts = id                   -- use the fully inferred/explicit txn+           | otherwise                          = originalTransaction  -- use the original txn (more or less)++-- Replace this transaction's postings with the original postings if any, but keep the+-- current possibly rewritten account names.+originalTransaction t = t { tpostings = map originalPostingPreservingAccount $ tpostings t }++-- Get the original posting if any, but keep the current possibly rewritten account name.+originalPostingPreservingAccount p = (originalPosting p) { paccount = paccount p }++-- XXX+-- tests_showTransactions = [+--   "showTransactions" ~: do++--    -- "print expenses" ~:+--    do+--     let opts = defreportopts{query_="expenses"}+--     d <- getCurrentDay+--     showTransactions opts (queryFromOpts d opts) samplejournal `is` unlines+--      ["2008/06/03 * eat & shop"+--      ,"    expenses:food                $1"+--      ,"    expenses:supplies            $1"+--      ,"    assets:cash                 $-2"+--      ,""+--      ]++--   -- , "print report with depth arg" ~:+--    do+--     let opts = defreportopts{depth_=Just 2}+--     d <- getCurrentDay+--     showTransactions opts (queryFromOpts d opts) samplejournal `is` unlines+--       ["2008/01/01 income"+--       ,"    assets:bank:checking            $1"+--       ,"    income:salary                  $-1"+--       ,""+--       ,"2008/06/01 gift"+--       ,"    assets:bank:checking            $1"+--       ,"    income:gifts                   $-1"+--       ,""+--       ,"2008/06/03 * eat & shop"+--       ,"    expenses:food                $1"+--       ,"    expenses:supplies            $1"+--       ,"    assets:cash                 $-2"+--       ,""+--       ,"2008/12/31 * pay off"+--       ,"    liabilities:debts               $1"+--       ,"    assets:bank:checking           $-1"+--       ,""+--       ]+--  ]++entriesReportAsCsv :: EntriesReport -> CSV+entriesReportAsCsv txns =+  ["txnidx","date","date2","status","code","description","comment","account","amount","commodity","credit","debit","posting-status","posting-comment"] :+  concatMap transactionToCSV txns++-- | Generate one CSV record per posting, duplicating the common transaction fields.+-- The txnidx field (transaction index) allows postings to be grouped back into transactions.+transactionToCSV :: Transaction -> CSV+transactionToCSV t =+  map (\p -> show idx:date:date2:status:code:description:comment:p)+   (concatMap postingToCSV $ tpostings t)+  where+    idx = tindex t+    description = T.unpack $ tdescription t+    date = showDate (tdate t)+    date2 = maybe "" showDate (tdate2 t)+    status = show $ tstatus t+    code = T.unpack $ tcode t+    comment = chomp $ strip $ T.unpack $ tcomment t++postingToCSV :: Posting -> CSV+postingToCSV p =+  map (\(a@(Amount {aquantity=q,acommodity=c})) ->+    let a_ = a{acommodity=""} in+    let amount = showAmount a_ in+    let commodity = T.unpack c in+    let credit = if q < 0 then showAmount $ negate a_ else "" in+    let debit  = if q >= 0 then showAmount a_ else "" in+    account:amount:commodity:credit:debit:status:comment:[])+   amounts+  where+    Mixed amounts = pamount p+    status = show $ pstatus p+    account = showAccountName Nothing (ptype p) (paccount p)+    comment = chomp $ strip $ T.unpack $ pcomment p++-- --match++-- | Print the transaction most closely and recently matching a description+-- (and the query, if any).+printMatch :: CliOpts -> Journal -> Text -> IO ()+printMatch CliOpts{reportopts_=ropts} j desc = do+  d <- getCurrentDay+  let q = queryFromOpts d ropts+  case similarTransaction' j q desc of+                Nothing -> putStrLn "no matches found."+                Just t  -> putStr $ showTransactionUnelided t++  where+    -- Identify the closest recent match for this description in past transactions.+    similarTransaction' :: Journal -> Query -> Text -> Maybe Transaction+    similarTransaction' j q desc+      | null historymatches = Nothing+      | otherwise           = Just $ snd $ head historymatches+      where+        historymatches = transactionsSimilarTo j q desc++-- tests++tests_Hledger_Cli_Commands_Print = TestList []+  -- tests_showTransactions
+ Hledger/Cli/Commands/Printunique.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE QuasiQuotes #-}++{-# LANGUAGE QuasiQuotes #-}++module Hledger.Cli.Commands.Printunique (+  printuniquemode+ ,printunique+) +where++import Data.List+import Data.Ord+import Data.String.Here+import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.Commands.Print++printuniquemode = hledgerCommandMode+  [here| print-unique+Print transactions which do not reuse an already-seen description.++FLAGS++Example:+```shell+$ cat unique.journal+1/1 test+ (acct:one)  1+2/2 test+ (acct:two)  2+$ LEDGER_FILE=unique.journal hledger print-unique+(-f option not supported)+2015/01/01 test+    (acct:one)             1+```+  |]+  []+  [generalflagsgroup1]+  []+  ([], Nothing)++printunique opts j@Journal{jtxns=ts} = do+  print' opts j{jtxns=uniquify ts}+  where+    uniquify = nubBy (\t1 t2 -> thingToCompare t1 == thingToCompare t2) . sortBy (comparing thingToCompare)+    thingToCompare = tdescription+    -- thingToCompare = tdate
+ Hledger/Cli/Commands/Register.hs view
@@ -0,0 +1,204 @@+{-|++A ledger-compatible @register@ command.++-}++{-# LANGUAGE CPP, OverloadedStrings #-}++module Hledger.Cli.Commands.Register (+  registermode+ ,register+ ,postingsReportAsText+ ,postingsReportItemAsText+ -- ,showPostingWithBalanceForVty+ ,tests_Hledger_Cli_Commands_Register+) where++import Data.List+import Data.Maybe+-- import Data.Text (Text)+import qualified Data.Text as T+import System.Console.CmdArgs.Explicit+import Text.CSV+import Test.HUnit++import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.Utils+++registermode = (defCommandMode $ ["register"] ++ aliases) {+  modeHelp = "show postings and running total. With --date2, show and sort by secondary date instead." `withAliases` aliases+ ,modeGroupFlags = Group {+     groupUnnamed = [+      flagNone ["cumulative"]         (\opts -> setboolopt "change" opts)+        "show running total from report start date (default)"+     ,flagNone ["historical","H"] (\opts -> setboolopt "historical" opts)+        "show historical running total/balance (includes postings before report start date)\n "+     ,flagNone ["average","A"] (\opts -> setboolopt "average" opts)+        "show running average of posting amounts instead of total (implies --empty)"+     ,flagNone ["related","r"] (\opts -> setboolopt "related" opts) "show postings' siblings instead"+     ,flagReq  ["width","w"] (\s opts -> Right $ setopt "width" s opts) "N"+      ("set output width (default: " +++#ifdef mingw32_HOST_OS+       show defaultWidth+#else+       "terminal width"+#endif+       ++ " or $COLUMNS). -wN,M sets description width as well."+       )+    ]+     ++ outputflags+    ,groupHidden = []+    ,groupNamed = [generalflagsgroup1]+    }+ }+  where aliases = ["r","reg"]++-- | Print a (posting) register report.+register :: CliOpts -> Journal -> IO ()+register opts@CliOpts{reportopts_=ropts} j = do+  d <- getCurrentDay+  let fmt = outputFormatFromOpts opts+      render | fmt=="csv" = const ((++"\n") . printCSV . postingsReportAsCsv)+             | otherwise  = postingsReportAsText+  writeOutput opts $ render opts $ postingsReport ropts (queryFromOpts d ropts) j++postingsReportAsCsv :: PostingsReport -> CSV+postingsReportAsCsv (_,is) =+  ["txnidx","date","description","account","amount","total"]+  :+  map postingsReportItemAsCsvRecord is++postingsReportItemAsCsvRecord :: PostingsReportItem -> Record+postingsReportItemAsCsvRecord (_, _, _, p, b) = [idx,date,desc,acct,amt,bal]+  where+    idx  = show $ maybe 0 tindex $ ptransaction p+    date = showDate $ postingDate p -- XXX csv should show date2 with --date2+    desc = T.unpack $ maybe "" tdescription $ ptransaction p+    acct = bracket $ T.unpack $ paccount p+      where+        bracket = case ptype p of+                             BalancedVirtualPosting -> (\s -> "["++s++"]")+                             VirtualPosting -> (\s -> "("++s++")")+                             _ -> id+    amt = showMixedAmountOneLineWithoutPrice $ pamount p+    bal = showMixedAmountOneLineWithoutPrice b++-- | Render a register report as plain text suitable for console output.+postingsReportAsText :: CliOpts -> PostingsReport -> String+postingsReportAsText opts (_,items) = unlines $ map (postingsReportItemAsText opts amtwidth balwidth) items+  where+    amtwidth = maximumStrict $ 12 : map (strWidth . showMixedAmount . itemamt) items+    balwidth = maximumStrict $ 12 : map (strWidth . showMixedAmount . itembal) items+    itemamt (_,_,_,Posting{pamount=a},_) = a+    itembal (_,_,_,_,a) = a++tests_postingsReportAsText = [+  "postingsReportAsText" ~: do+  -- "unicode in register layout" ~: do+    j <- readJournal'+      "2009/01/01 * медвежья шкура\n  расходы:покупки  100\n  актив:наличные\n"+    let opts = defreportopts+    (postingsReportAsText defcliopts $ postingsReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is` unlines+      ["2009/01/01 медвежья шкура       расходы:покупки                100           100"+      ,"                                актив:наличные                -100             0"]+ ]++-- | Render one register report line item as plain text. Layout is like so:+-- @+-- <---------------- width (specified, terminal width, or 80) -------------------->+-- date (10)  description           account              amount (12)   balance (12)+-- DDDDDDDDDD dddddddddddddddddddd  aaaaaaaaaaaaaaaaaaa  AAAAAAAAAAAA  AAAAAAAAAAAA+-- @+-- If description's width is specified, account will use the remaining space.+-- Otherwise, description and account divide up the space equally.+--+-- With a report interval, the layout is like so:+-- @+-- <---------------- width (specified, terminal width, or 80) -------------------->+-- date (21)              account                        amount (12)   balance (12)+-- DDDDDDDDDDDDDDDDDDDDD  aaaaaaaaaaaaaaaaaaaaaaaaaaaaa  AAAAAAAAAAAA  AAAAAAAAAAAA+-- @+--+-- date and description are shown for the first posting of a transaction only.+--+-- Returns a string which can be multi-line, eg if the running balance+-- has multiple commodities. Does not yet support formatting control+-- like balance reports.+--+postingsReportItemAsText :: CliOpts -> Int -> Int -> PostingsReportItem -> String+postingsReportItemAsText opts preferredamtwidth preferredbalwidth (mdate, menddate, mdesc, p, b) =+  -- use elide*Width to be wide-char-aware+  -- trace (show (totalwidth, datewidth, descwidth, acctwidth, amtwidth, balwidth)) $+  intercalate "\n" $+    [concat [fitString (Just datewidth) (Just datewidth) True True date+            ," "+            ,fitString (Just descwidth) (Just descwidth) True True desc+            ,"  "+            ,fitString (Just acctwidth) (Just acctwidth) True True acct+            ,"  "+            ,fitString (Just amtwidth) (Just amtwidth) True False amtfirstline+            ,"  "+            ,fitString (Just balwidth) (Just balwidth) True False balfirstline+            ]]+    +++    [concat [spacer+            ,fitString (Just amtwidth) (Just amtwidth) True False a+            ,"  "+            ,fitString (Just balwidth) (Just balwidth) True False b+            ]+     | (a,b) <- zip amtrest balrest+     ]+    where+      -- calculate widths+      (totalwidth,mdescwidth) = registerWidthsFromOpts opts+      (datewidth, date) = case (mdate,menddate) of+                            (Just _, Just _)   -> (21, showDateSpan (DateSpan mdate menddate))+                            (Nothing, Just _)  -> (21, "")+                            (Just d, Nothing)  -> (10, showDate d)+                            _                  -> (10, "")+      (amtwidth, balwidth)+        | shortfall <= 0 = (preferredamtwidth, preferredbalwidth)+        | otherwise      = (adjustedamtwidth, adjustedbalwidth)+        where+          mincolwidth = 2 -- columns always show at least an ellipsis+          maxamtswidth = max 0 (totalwidth - (datewidth + 1 + mincolwidth + 2 + mincolwidth + 2 + 2))+          shortfall = (preferredamtwidth + preferredbalwidth) - maxamtswidth+          amtwidthproportion = fromIntegral preferredamtwidth / fromIntegral (preferredamtwidth + preferredbalwidth)+          adjustedamtwidth = round $ amtwidthproportion * fromIntegral maxamtswidth+          adjustedbalwidth = maxamtswidth - adjustedamtwidth++      remaining = totalwidth - (datewidth + 1 + 2 + amtwidth + 2 + balwidth)+      (descwidth, acctwidth)+        | hasinterval = (0, remaining - 2)+        | otherwise   = (w, remaining - 2 - w)+        where+            hasinterval = isJust menddate+            w = fromMaybe ((remaining - 2) `div` 2) mdescwidth++      -- gather content+      desc = fromMaybe "" mdesc+      acct = parenthesise $ T.unpack $ elideAccountName awidth $ paccount p+         where+          (parenthesise, awidth) =+            case ptype p of+              BalancedVirtualPosting -> (\s -> "["++s++"]", acctwidth-2)+              VirtualPosting         -> (\s -> "("++s++")", acctwidth-2)+              _                      -> (id,acctwidth)+      amt = showMixedAmountWithoutPrice $ pamount p+      bal = showMixedAmountWithoutPrice b+      -- alternate behaviour, show null amounts as 0 instead of blank+      -- amt = if null amt' then "0" else amt'+      -- bal = if null bal' then "0" else bal'+      (amtlines, ballines) = (lines amt, lines bal)+      (amtlen, ballen) = (length amtlines, length ballines)+      numlines = max 1 (max amtlen ballen)+      (amtfirstline:amtrest) = take numlines $ amtlines ++ repeat "" -- posting amount is top-aligned+      (balfirstline:balrest) = take numlines $ replicate (numlines - ballen) "" ++ ballines -- balance amount is bottom-aligned+      spacer = replicate (totalwidth - (amtwidth + 2 + balwidth)) ' '++tests_Hledger_Cli_Commands_Register :: Test+tests_Hledger_Cli_Commands_Register = TestList+  tests_postingsReportAsText
+ Hledger/Cli/Commands/Registermatch.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++module Hledger.Cli.Commands.Registermatch (+  registermatchmode+ ,registermatch+) +where++import Data.Char (toUpper)+import Data.List+import Data.String.Here+import qualified Data.Text as T+import Hledger+import Hledger.Cli.CliOptions+import Hledger.Cli.Commands.Register++registermatchmode = hledgerCommandMode+  [here| register-match+Print the one posting whose transaction description is closest to DESC, +in the style of the register command.+If there are multiple equally good matches, it shows the most recent.+Query options (options, not arguments) can be used to restrict the search space.+Helps ledger-autosync detect already-seen transactions when importing.+  |]+  []+  [generalflagsgroup1]+  []+  ([], Nothing)++registermatch :: CliOpts -> Journal -> IO ()+registermatch opts@CliOpts{rawopts_=rawopts,reportopts_=ropts} j = do+  let args' = listofstringopt "args" rawopts+  case args' of+    [desc] -> do+        d <- getCurrentDay+        let q  = queryFromOptsOnly d ropts+            (_,pris) = postingsReport ropts q j+            ps = [p | (_,_,_,p,_) <- pris]+        case similarPosting ps desc of+          Nothing -> putStrLn "no matches found."+          Just p  -> putStr $ postingsReportAsText opts ("",[pri])+                     where pri = (Just (postingDate p)+                                 ,Nothing+                                 ,Just $ T.unpack (maybe "" tdescription $ ptransaction p)+                                 ,p+                                 ,0)+    _ -> putStrLn "please provide one description argument."++-- Identify the closest recent match for this description in the given date-sorted postings.+similarPosting :: [Posting] -> String -> Maybe Posting+similarPosting ps desc =+  let matches =+          sortBy compareRelevanceAndRecency+                     $ filter ((> threshold).fst)+                     [(maybe 0 (\t -> compareDescriptions desc (T.unpack $ tdescription t)) (ptransaction p), p) | p <- ps]+              where+                compareRelevanceAndRecency (n1,p1) (n2,p2) = compare (n2,postingDate p2) (n1,postingDate p1)+                threshold = 0+  in case matches of []  -> Nothing+                     m:_ -> Just $ snd m++-- -- Identify the closest recent match for this description in past transactions.+-- similarTransaction :: Journal -> Query -> String -> Maybe Transaction+-- similarTransaction j q desc =+--   case historymatches = transactionsSimilarTo j q desc of+--     ((,t):_) = Just t+--     []       = Nothing++compareDescriptions :: [Char] -> [Char] -> Double+compareDescriptions s t = compareStrings s' t'+    where s' = simplify s+          t' = simplify t+          simplify = filter (not . (`elem` ("0123456789"::String)))++-- | Return a similarity measure, from 0 to 1, for two strings.+-- This is Simon White's letter pairs algorithm from+-- http://www.catalysoft.com/articles/StrikeAMatch.html+-- with a modification for short strings.+compareStrings :: String -> String -> Double+compareStrings "" "" = 1+compareStrings (_:[]) "" = 0+compareStrings "" (_:[]) = 0+compareStrings (a:[]) (b:[]) = if toUpper a == toUpper b then 1 else 0+compareStrings s1 s2 = 2.0 * fromIntegral i / fromIntegral u+    where+      i = length $ intersect pairs1 pairs2+      u = length pairs1 + length pairs2+      pairs1 = wordLetterPairs $ uppercase s1+      pairs2 = wordLetterPairs $ uppercase s2++wordLetterPairs = concatMap letterPairs . words++letterPairs (a:b:rest) = [a,b] : letterPairs (b:rest)+letterPairs _ = []+
+ Hledger/Cli/Commands/Rewrite.hs view
@@ -0,0 +1,276 @@+{-# LANGUAGE OverloadedStrings, LambdaCase, DeriveTraversable, ViewPatterns, QuasiQuotes #-}++module Hledger.Cli.Commands.Rewrite (+  rewritemode+ ,rewrite+) +where++import Control.Monad.Writer+import Data.List (sortOn, foldl')+import Data.String.Here+import qualified Data.Text as T+import Hledger+import Hledger.Data.AutoTransaction (runModifierTransaction)+import Hledger.Cli.CliOptions+import Hledger.Cli.Commands.Print+--import Hledger.Cli hiding (outputflags)+import System.Console.CmdArgs.Explicit+import Text.Printf+import Text.Megaparsec+import qualified Data.Algorithm.Diff as D++rewritemode = hledgerCommandMode+  [here| rewrite+Print all transactions, adding custom postings to the matched ones.++FLAGS++This is a start at a generic rewriter of transaction entries.+It reads the default journal and prints the transactions, like print,+but adds one or more specified postings to any transactions matching QUERY.+The posting amounts can be fixed, or a multiplier of the existing transaction's first posting amount. ++Examples:+```+hledger-rewrite.hs ^income --add-posting '(liabilities:tax)  *.33  ; income tax' --add-posting '(reserve:gifts)  $100'+hledger-rewrite.hs expenses:gifts --add-posting '(reserve:gifts)  *-1"'+hledger-rewrite.hs -f rewrites.hledger+```+rewrites.hledger may consist of entries like:+```+= ^income amt:<0 date:2017+  (liabilities:tax)  *0.33  ; tax on income+  (reserve:grocery)  *0.25  ; reserve 25% for grocery+  (reserve:)  *0.25  ; reserve 25% for grocery+```+Note the single quotes to protect the dollar sign from bash, +and the two spaces between account and amount.++More:++```shell+$ hledger rewrite -- [QUERY]        --add-posting "ACCT  AMTEXPR" ...+$ hledger rewrite -- ^income        --add-posting '(liabilities:tax)  *.33'+$ hledger rewrite -- expenses:gifts --add-posting '(budget:gifts)  *-1"'+$ hledger rewrite -- ^income        --add-posting '(budget:foreign currency)  *0.25 JPY; diversify'+```++Argument for `--add-posting` option is a usual posting of transaction with an+exception for amount specification. More precisely, you can use `'*'` (star+symbol) before the amount to indicate that that this is a factor for an+amount of original matched posting.  If the amount includes a commodity name,+the new posting amount will be in the new commodity; otherwise, it will be in+the matched posting amount's commodity.++#### Re-write rules in a file++During the run this tool will execute so called+["Automated Transactions"](http://ledger-cli.org/3.0/doc/ledger3.html#Automated-Transactions)+found in any journal it process. I.e instead of specifying this operations in+command line you can put them in a journal file.++```shell+$ rewrite-rules.journal+```++Make contents look like this:++```journal+= ^income+    (liabilities:tax)  *.33++= expenses:gifts+    budget:gifts  *-1+    assets:budget  *1+```++Note that `'='` (equality symbol) that is used instead of date in transactions+you usually write. It indicates the query by which you want to match the+posting to add new ones.++```shell+$ hledger rewrite -- -f input.journal -f rewrite-rules.journal > rewritten-tidy-output.journal+```++This is something similar to the commands pipeline:++```shell+$ hledger rewrite -- -f input.journal '^income' --add-posting '(liabilities:tax)  *.33' \+  | hledger rewrite -- -f - expenses:gifts      --add-posting 'budget:gifts  *-1'       \+                                                --add-posting 'assets:budget  *1'       \+  > rewritten-tidy-output.journal+```++It is important to understand that relative order of such entries in journal is+important. You can re-use result of previously added postings.++#### Diff output format++To use this tool for batch modification of your journal files you may find+useful output in form of unified diff.++```shell+$ hledger rewrite -- --diff -f examples/sample.journal '^income' --add-posting '(liabilities:tax)  *.33'+```++Output might look like:++```diff+--- /tmp/examples/sample.journal++++ /tmp/examples/sample.journal+@@ -18,3 +18,4 @@+ 2008/01/01 income+-    assets:bank:checking  $1++    assets:bank:checking            $1+     income:salary++    (liabilities:tax)                0+@@ -22,3 +23,4 @@+ 2008/06/01 gift+-    assets:bank:checking  $1++    assets:bank:checking            $1+     income:gifts++    (liabilities:tax)                0+```++If you'll pass this through `patch` tool you'll get transactions containing the+posting that matches your query be updated. Note that multiple files might be+update according to list of input files specified via `--file` options and+`include` directives inside of these files.++Be careful. Whole transaction being re-formatted in a style of output from+`hledger print`.++See also: ++https://github.com/simonmichael/hledger/issues/99++  |]+  [flagReq ["add-posting"] (\s opts -> Right $ setopt "add-posting" s opts) "'ACCT  AMTEXPR'"+           "add a posting to ACCT, which may be parenthesised. AMTEXPR is either a literal amount, or *N which means the transaction's first matched amount multiplied by N (a decimal number). Two spaces separate ACCT and AMTEXPR."+  ,flagNone ["diff"] (setboolopt "diff") "generate diff suitable as an input for patch tool"+  ]+  [generalflagsgroup1]+  []+  ([], Just $ argsFlag "[QUERY] --add-posting \"ACCT  AMTEXPR\" ...")+------------------------------------------------------------------------------++-- TODO regex matching and interpolating matched name in replacement+-- TODO interpolating match groups in replacement+-- TODO allow using this on unbalanced entries, eg to rewrite while editing++rewrite opts@CliOpts{rawopts_=rawopts,reportopts_=ropts} j@Journal{jtxns=ts} = do +  d <- getCurrentDay+  let q = queryFromOpts d ropts+  modifier <- modifierTransactionFromOpts rawopts+  -- create re-writer+  let modifiers = modifier : jmodifiertxns j+      -- Note that some query matches require transaction. Thus modifiers+      -- pipeline should include txnTieKnot on every step.+      modifier' = foldr (flip (.) . fmap txnTieKnot . runModifierTransaction q) id modifiers+  -- rewrite matched transactions+  let j' = j{jtxns=map modifier' ts}+  -- run the print command, showing all transactions+  outputFromOpts rawopts opts{reportopts_=ropts{query_=""}} j j'++postingp' :: T.Text -> IO Posting+postingp' t = runErroringJournalParser (postingp Nothing <* eof) t' >>= \case+        Left err -> fail err+        Right p -> return p+    where t' = " " <> t <> "\n" -- inject space and newline for proper parsing++modifierTransactionFromOpts :: RawOpts -> IO ModifierTransaction+modifierTransactionFromOpts opts = do+    postings <- mapM (postingp' . stripquotes . T.pack) $ listofstringopt "add-posting" opts+    return+        ModifierTransaction { mtvalueexpr = T.empty, mtpostings = postings }++outputFromOpts :: RawOpts -> (CliOpts -> Journal -> Journal -> IO ())+outputFromOpts opts+    | boolopt "diff" opts = const diffOutput+    | otherwise = flip (const print')++diffOutput :: Journal -> Journal -> IO ()+diffOutput j j' = do+    let changed = [(originalTransaction t, originalTransaction t') | (t, t') <- zip (jtxns j) (jtxns j'), t /= t']+    putStr $ renderPatch $ map (uncurry $ diffTxn j) changed++type Chunk = (GenericSourcePos, [DiffLine String])++-- | Render list of changed lines as a unified diff+--+-- >>> putStr $ renderPatch [(GenericSourcePos "a" 1 1, [D.First "x", D.Second "y"])]+-- --- a+-- +++ a+-- @@ -1,1 +1,1 @@+-- -x+-- +y+-- >>> putStr $ renderPatch [(GenericSourcePos "a" 1 1, [D.Both "x" "x", D.Second "y"]), (GenericSourcePos "a" 5 1, [D.Second "z"])]+-- --- a+-- +++ a+-- @@ -1,1 +1,2 @@+--  x+-- +y+-- @@ -5,0 +6,1 @@+-- +z+-- >>> putStr $ renderPatch [(GenericSourcePos "a" 1 1, [D.Both "x" "x", D.Second "y"]), (GenericSourcePos "b" 5 1, [D.Second "z"])]+-- --- a+-- +++ a+-- @@ -1,1 +1,2 @@+--  x+-- +y+-- --- b+-- +++ b+-- @@ -5,0 +5,1 @@+-- +z+renderPatch :: [Chunk] -> String+renderPatch = go Nothing . sortOn fst where+    go _ [] = ""+    go Nothing cs@((sourceFilePath -> fp, _):_) = fileHeader fp ++ go (Just (fp, 0)) cs+    go (Just (fp, _)) cs@((sourceFilePath -> fp', _):_) | fp /= fp' = go Nothing cs+    go (Just (fp, offs)) ((sourceFirstLine -> lineno, diffs):cs) = chunkHeader ++ chunk ++ go (Just (fp, offs + adds - dels)) cs+        where+            chunkHeader = printf "@@ -%d,%d +%d,%d @@\n" lineno dels (lineno+offs) adds where+            (dels, adds) = foldl' countDiff (0, 0) diffs+            chunk = concatMap renderLine diffs+    fileHeader fp = printf "--- %s\n+++ %s\n" fp fp++    countDiff (dels, adds) = \case+        Del _  -> (dels + 1, adds)+        Add _ -> (dels    , adds + 1)+        Ctx _ -> (dels + 1, adds + 1)++    renderLine = \case+        Del s -> '-' : s ++ "\n"+        Add s -> '+' : s ++ "\n"+        Ctx s -> ' ' : s ++ "\n"++diffTxn :: Journal -> Transaction -> Transaction -> Chunk+diffTxn j t t' =+        case tsourcepos t of+            GenericSourcePos fp lineno _ -> (GenericSourcePos fp (lineno+1) 1, diffs) where+                -- TODO: use range and produce two chunks: one removes part of+                --       original file, other adds transaction to new file with+                --       suffix .ledger (generated). I.e. move transaction from one file to another.+                diffs :: [DiffLine String]+                diffs = concat . map (traverse showPostingLines . mapDiff) $ D.getDiff (tpostings t) (tpostings t')+            pos@(JournalSourcePos fp (line, line')) -> (pos, diffs) where+                -- We do diff for original lines vs generated ones. Often leads+                -- to big diff because of re-format effect.+                diffs :: [DiffLine String]+                diffs = map mapDiff $ D.getDiff source changed'+                source | Just contents <- lookup fp $ jfiles j = map T.unpack . drop (line-1) . take line' $ T.lines contents+                       | otherwise = []+                changed = lines $ showTransactionUnelided t'+                changed' | null changed = changed+                         | null $ last changed = init changed+                         | otherwise = changed++data DiffLine a = Del a | Add a | Ctx a+    deriving (Show, Functor, Foldable, Traversable)++mapDiff :: D.Diff a -> DiffLine a+mapDiff = \case+    D.First x -> Del x+    D.Second x -> Add x+    D.Both x _ -> Ctx x
+ Hledger/Cli/Commands/Stats.hs view
@@ -0,0 +1,112 @@+{-|++Print some statistics for the journal.++-}++{-# LANGUAGE OverloadedStrings #-}++module Hledger.Cli.Commands.Stats (+  statsmode+ ,stats+)+where++import Data.List+import Data.Maybe+import Data.Ord+import Data.HashSet (size, fromList)+-- import Data.Text (Text)+import qualified Data.Text as T+import Data.Time.Calendar+import System.Console.CmdArgs.Explicit+import Text.Printf+import qualified Data.Map as Map++import Hledger+import Hledger.Cli.CliOptions+import Prelude hiding (putStr)+import Hledger.Cli.Utils (writeOutput)+++statsmode = (defCommandMode $ ["stats"] ++ aliases) {+  modeHelp = "show some journal statistics" `withAliases` aliases+ ,modeGroupFlags = Group {+     groupUnnamed = [+        flagReq  ["output-file","o"]   (\s opts -> Right $ setopt "output-file" s opts) "FILE" "write output to FILE.  A file extension matching one of the above formats selects that format."+        ]+    ,groupHidden = []+    ,groupNamed = [generalflagsgroup1]+    }+ }+  where aliases = []++-- like Register.summarisePostings+-- | Print various statistics for the journal.+stats :: CliOpts -> Journal -> IO ()+stats opts@CliOpts{reportopts_=reportopts_} j = do+  d <- getCurrentDay+  let q = queryFromOpts d reportopts_+      l = ledgerFromJournal q j+      reportspan = (ledgerDateSpan l) `spanDefaultsFrom` (queryDateSpan False q)+      intervalspans = splitSpan (interval_ reportopts_) reportspan+      showstats = showLedgerStats l d+      s = intercalate "\n" $ map showstats intervalspans+  writeOutput opts s++showLedgerStats :: Ledger -> Day -> DateSpan -> String+showLedgerStats l today span =+    unlines $ map (\(label,value) -> concatBottomPadded [printf fmt1 label, value]) stats+    where+      fmt1 = "%-" ++ show w1 ++ "s: "+      -- fmt2 = "%-" ++ show w2 ++ "s"+      w1 = maximum $ map (length . fst) stats+      -- w2 = maximum $ map (length . show . snd) stats+      stats = [+         ("Main file" :: String, path) -- ++ " (from " ++ source ++ ")")+        ,("Included files", unlines $ drop 1 $ journalFilePaths j)+        ,("Transactions span", printf "%s to %s (%d days)" (start span) (end span) days)+        ,("Last transaction", maybe "none" show lastdate ++ showelapsed lastelapsed)+        ,("Transactions", printf "%d (%0.1f per day)" tnum txnrate)+        ,("Transactions last 30 days", printf "%d (%0.1f per day)" tnum30 txnrate30)+        ,("Transactions last 7 days", printf "%d (%0.1f per day)" tnum7 txnrate7)+        ,("Payees/descriptions", show $ size $ fromList $ map (tdescription) ts)+        ,("Accounts", printf "%d (depth %d)" acctnum acctdepth)+        ,("Commodities", printf "%s (%s)" (show $ length cs) (T.intercalate ", " cs))+      -- Transactions this month     : %(monthtxns)s (last month in the same period: %(lastmonthtxns)s)+      -- Unmarked transactions      : %(unmarked)s+      -- Days since reconciliation   : %(reconcileelapsed)s+      -- Days since last transaction : %(recentelapsed)s+       ]+           where+             j = ljournal l+             path = journalFilePath j+             ts = sortBy (comparing tdate) $ filter (spanContainsDate span . tdate) $ jtxns j+             as = nub $ map paccount $ concatMap tpostings ts+             cs = Map.keys $ commodityStylesFromAmounts $ concatMap amounts $ map pamount $ concatMap tpostings ts+             lastdate | null ts = Nothing+                      | otherwise = Just $ tdate $ last ts+             lastelapsed = maybe Nothing (Just . diffDays today) lastdate+             showelapsed Nothing = ""+             showelapsed (Just days) = printf " (%d %s)" days' direction+                                       where days' = abs days+                                             direction | days >= 0 = "days ago" :: String+                                                       | otherwise = "days from now"+             tnum = length ts+             start (DateSpan (Just d) _) = show d+             start _ = ""+             end (DateSpan _ (Just d)) = show d+             end _ = ""+             days = fromMaybe 0 $ daysInSpan span+             txnrate | days==0 = 0+                     | otherwise = fromIntegral tnum / fromIntegral days :: Double+             tnum30 = length $ filter withinlast30 ts+             withinlast30 t = d >= addDays (-30) today && (d<=today) where d = tdate t+             txnrate30 = fromIntegral tnum30 / 30 :: Double+             tnum7 = length $ filter withinlast7 ts+             withinlast7 t = d >= addDays (-7) today && (d<=today) where d = tdate t+             txnrate7 = fromIntegral tnum7 / 7 :: Double+             acctnum = length as+             acctdepth | null as = 0+                       | otherwise = maximum $ map accountNameLevel as+
+ Hledger/Cli/Commands/Tags.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE QuasiQuotes #-}++module Hledger.Cli.Commands.Tags (+  tagsmode+ ,tags+) +where++import Data.List+import Data.String.Here+import qualified Data.Text.IO as T+import Hledger+import Hledger.Cli.CliOptions++tagsmode = hledgerCommandMode+  [here| tags+List all the tag names in use.+With a query, only matched transactions' tags are shown.+Reads the default journal file, or another specified with -f.+FLAGS+  |]+  [] -- [flagNone ["strict"] (\opts -> setboolopt "strict" opts) "makes date comparing strict"] -- +  [generalflagsgroup1]+  []+  ([], Just $ argsFlag "[QUERY]")++tags CliOpts{rawopts_=_rawopts,reportopts_=ropts} j = do+  d <- getCurrentDay+  let+    q = queryFromOpts d ropts+    ts = filter (q `matchesTransaction`) $ jtxns $ journalSelectingAmountFromOpts ropts j+    tags = nub $ sort $ map fst $ concatMap transactionAllTags ts+  mapM_ T.putStrLn tags
Hledger/Cli/CompoundBalanceCommand.hs view
@@ -12,20 +12,22 @@  ,compoundBalanceCommand ) where -import Control.Monad (unless)-import Data.List (intercalate, foldl', isPrefixOf)+import Data.List (intercalate, foldl') import Data.Maybe (fromMaybe) import Data.Monoid (Sum(..), (<>))+import Data.Tuple.HT (uncurry3) import System.Console.CmdArgs.Explicit as C+import Text.CSV import Text.Tabular as T  import Hledger-import Hledger.Cli.Balance+import Hledger.Cli.Commands.Balance import Hledger.Cli.CliOptions+import Hledger.Cli.Utils (writeOutput)  -- | Description of a compound balance report command,  -- from which we generate the command's cmdargs mode and IO action.--- A compound balance report shows one or more sections/subreports, +-- A compound balance report command shows one or more sections/subreports,  -- each with its own title and subtotals row, in a certain order,  -- plus a grand totals row if there's more than one section. -- Examples are the balancesheet, cashflow and incomestatement commands.@@ -34,7 +36,9 @@   cbcaliases  :: [String],                      -- ^ command aliases   cbchelp     :: String,                        -- ^ command line help   cbctitle    :: String,                        -- ^ overall report title-  cbcqueries  :: [(String, Journal -> Query)],  -- ^ title and (journal-parameterised) query for each subreport+  cbcqueries  :: [(String, Journal -> Query, Maybe NormalBalance)],+    -- ^ title, journal-parameterised query, and expected normal balance for each subreport.+    -- The normal balance helps --sort-amount know how to sort negative amounts.    cbctype     :: BalanceType                    -- ^ the type of "balance" this report shows (overrides command line flags) } @@ -64,6 +68,9 @@      ,flagNone ["no-elide"] (\opts -> setboolopt "no-elide" opts) "don't squash boring parent accounts (in tree mode)"      ,flagReq  ["format"] (\s opts -> Right $ setopt "format" s opts) "FORMATSTR" "use this custom line format (in simple reports)"      ,flagNone ["pretty-tables"] (\opts -> setboolopt "pretty-tables" opts) "use unicode when displaying tables"+     ,flagNone ["sort-amount","S"] (\opts -> setboolopt "sort-amount" opts) "sort by amount instead of account name"+     ,outputFormatFlag+     ,outputFileFlag      ]     ,groupHidden = []     ,groupNamed = [generalflagsgroup1]@@ -76,7 +83,7 @@  -- | Generate a runnable command from a compound balance command specification. compoundBalanceCommand :: CompoundBalanceCommandSpec -> (CliOpts -> Journal -> IO ())-compoundBalanceCommand CompoundBalanceCommandSpec{..} CliOpts{command_=cmd, reportopts_=ropts, rawopts_=rawopts} j = do+compoundBalanceCommand CompoundBalanceCommandSpec{..} opts@CliOpts{command_=cmd, reportopts_=ropts, rawopts_=rawopts} j = do     d <- getCurrentDay     let       -- use the default balance type for this report, unless the user overrides  @@ -95,10 +102,12 @@               PeriodChange      -> "(Balance Changes)"               CumulativeChange  -> "(Cumulative Ending Balances)"               HistoricalBalance -> "(Historical Ending Balances)"-      -- set balance type and possibly tree mode in the report options. Some older notes: -      -- For --historical/--cumulative, we must use multiBalanceReport (this forces --no-elide).-      -- These settings format the output in a way that we can convert to a normal balance report -      -- using singleBalanceReport, see Balance.hs for more information.+      -- Set balance type in the report options.+      -- XXX Also, use tree mode (by default, at least?) if --cumulative/--historical +      -- are used in single column mode, since in that situation we will be using +      -- singleBalanceReport which does not support eliding boring parents,+      -- and tree mode hides this.. or something.. +      -- see also compoundBalanceCommandSingleColumnReport, #565         ropts'         | not (flat_ ropts) &&            interval_ ropts==NoInterval && @@ -107,107 +116,232 @@         | otherwise             = ropts{balancetype_=balancetype}       userq = queryFromOpts d ropts'+      format = outputFormatFromOpts opts      case interval_ ropts' of        -- single-column report+      -- TODO refactor, support output format like multi column        NoInterval -> do-        let (subreportstr, total) = foldMap (uncurry (compoundBalanceCommandSingleColumnReport ropts' userq j)) cbcqueries-        putStrLn $ title ++ "\n"-        mapM_ putStrLn subreportstr-        unless (no_total_ ropts' || cmd=="cashflow") . mapM_ putStrLn $ -- TODO temp-          [ "Total:"-          , "--------------------"-          , padLeftWide 20 $ showamt (getSum total)-          ]-        where-          showamt | color_ ropts' = cshowMixedAmountWithoutPrice-                  | otherwise    = showMixedAmountWithoutPrice-          +        let+          -- concatenate the rendering and sum the totals from each subreport+          (subreportstr, total) = +            foldMap (uncurry3 (compoundBalanceCommandSingleColumnReport ropts' userq j)) cbcqueries++        writeOutput opts $ unlines $+          [title ++ "\n"] +++          subreportstr +++          if (no_total_ ropts' || cmd=="cashflow")+           then []+           else+             [ "Total:"+             , "--------------------"+             , padLeftWide 20 $ showamt (getSum total)+             , ""+             ]+             where+               showamt | color_ ropts' = cshowMixedAmountWithoutPrice+                       | otherwise    = showMixedAmountWithoutPrice+       -- multi-column report       _ -> do         let-          (subreporttables, subreporttotals, Sum overalltotal) = foldMap (uncurry (compoundBalanceCommandMultiColumnReports ropts' userq j)) cbcqueries-          overalltable = case subreporttables of-            t1:ts -> foldl' concatTables t1 ts-            []    -> T.empty-          overalltable'-            | no_total_ ropts' || length cbcqueries == 1 =-                overalltable-            | otherwise =-                overalltable-                +====+-                row "Total" overalltotals'-              where-                overalltotals = case subreporttotals of-                  [] -> []-                  ts -> foldl' (zipWith (+)) zeros ts'-                    where-                      -- A subreport might be empty and have no subtotals, count those as zeroes (#588).-                      -- Varying-length subtotals rows are handled similarly, though that is not expected to happen.  -                      len = maximum $ map length ts-                      ts' = [take len $ as ++ repeat nullmixedamt | as <- ts]-                      zeros = replicate len nullmixedamt-                overalltotals'-                  | null overalltotals = []-                  | otherwise =  overalltotals-                                 ++ (if row_total_ ropts' then [overalltotal]   else [])-                                 ++ (if average_ ropts'   then [overallaverage] else [])-                    where-                      overallaverage = overalltotal `divideMixedAmount` fromIntegral (length overalltotals)-        putStrLn title-        putStrLn $ renderBalanceReportTable ropts' overalltable'---- Add the second table below the first, discarding its column headings.-concatTables (Table hLeft hTop dat) (Table hLeft' _ dat') =-    Table (T.Group DoubleLine [hLeft, hLeft']) hTop (dat ++ dat')+          -- make a CompoundBalanceReport+          namedsubreports = +            map (\(subreporttitle, subreportq, subreportnormalsign) -> +                  (subreporttitle, compoundBalanceSubreport ropts' userq j subreportq subreportnormalsign)) +                cbcqueries+          subtotalrows = [coltotals | MultiBalanceReport (_,_,(coltotals,_,_)) <- map snd namedsubreports]+          overalltotals = case subtotalrows of+            [] -> ([], nullmixedamt, nullmixedamt)+            rs ->+              -- Sum the subtotals in each column.+              -- A subreport might be empty and have no subtotals, count those as zeros (#588).+              -- Short subtotals rows are also implicitly padded with zeros, though that is not expected to happen.  +              let+                numcols = maximum $ map length rs  -- depends on non-null ts+                zeros = replicate numcols nullmixedamt+                rs' = [take numcols $ as ++ repeat nullmixedamt | as <- rs]+                coltotals = foldl' (zipWith (+)) zeros rs'+                grandtotal = sum coltotals+                grandavg | null coltotals = nullmixedamt+                         | otherwise      = grandtotal `divideMixedAmount` fromIntegral (length coltotals)+              in +                (coltotals, grandtotal, grandavg)+          cbr =+            (title+            ,namedsubreports+            ,overalltotals +            )+        -- render appropriately+        writeOutput opts $+          case format of+            "csv" -> printCSV (compoundBalanceReportAsCsv ropts cbr) ++ "\n"+            _     -> compoundBalanceReportAsText ropts' cbr --- | Run one subreport for a single-column compound balance command.--- Currently this returns the plain text rendering of the subreport,--- and its total.+-- | Run one subreport for a compound balance command in single-column mode.+-- Currently this returns the plain text rendering of the subreport, and its total.+-- The latter is wrapped in a Sum for easy monoidal combining. compoundBalanceCommandSingleColumnReport     :: ReportOpts     -> Query     -> Journal     -> String     -> (Journal -> Query)+    -> Maybe NormalBalance     -> ([String], Sum MixedAmount)-compoundBalanceCommandSingleColumnReport ropts q0 j t q = ([view], Sum amt)-    where-      q' = And [q0, q j]-      rep@(_ , amt)-        -- For --historical/--cumulative, we must use multiBalanceReport.-        -- (This forces --no-elide.)-        -- See Balance.hs's implementation of 'balance' for more information-        | balancetype_ ropts `elem` [HistoricalBalance, CumulativeChange]-            = singleBalanceReport ropts q' j-        | otherwise-            = balanceReport ropts q' j-      view = intercalate "\n" [t <> ":", balanceReportAsText ropts rep]+compoundBalanceCommandSingleColumnReport ropts userq j subreporttitle subreportqfn subreportnormalsign = +  ([subreportstr], Sum total)+  where+    q = And [subreportqfn j, userq]+    ropts' = ropts{normalbalance_=subreportnormalsign}+    r@(_,total)+      -- XXX For --historical/--cumulative, we must use singleBalanceReport;+      -- otherwise we use balanceReport -- because it supports eliding boring parents. +      -- See also compoundBalanceCommand, Balance.hs -> balance.+      | balancetype_ ropts `elem` [CumulativeChange, HistoricalBalance] = singleBalanceReport ropts' q j+      | otherwise                                                       = balanceReport       ropts' q j+    subreportstr = intercalate "\n" [subreporttitle <> ":", balanceReportAsText ropts r] --- | Run all the subreports for a multi-column compound balance command.--- Currently this returns a table of rendered balance amounts for each --- subreport (including a totals row), the totals row for each subreport --- (again, as mixedamounts), and the grand total.-compoundBalanceCommandMultiColumnReports-    :: ReportOpts-    -> Query-    -> Journal-    -> String-    -> (Journal -> Query)-    -> ([Table String String MixedAmount], [[MixedAmount]], Sum MixedAmount)-compoundBalanceCommandMultiColumnReports ropts q0 j t q = ([tabl], [coltotals], Sum tot)-    where-      singlesection = "Cash" `isPrefixOf` t -- TODO temp-      ropts' = ropts { no_total_ = singlesection && no_total_ ropts, empty_ = True }-      q' = And [q0, q j]-      MultiBalanceReport (dates, rows, (coltotals,tot,avg)) =-          multiBalanceReport ropts' q' j-      rows' | empty_ ropts = rows-            | otherwise    = filter (not . emptyRow) rows-        where-          emptyRow (_,_,_,amts,_,_) = all isZeroMixedAmount amts-      r = MultiBalanceReport (dates, rows', (coltotals, tot, avg))-      Table hLeft hTop dat = balanceReportAsTable ropts' r-      tabl = Table (T.Group SingleLine [Header t, hLeft]) hTop ([]:dat)+-- | A compound balance report has:+--+-- * an overall title+--+-- * one or more named multi balance reports, with the same column headings+--+-- * a list of overall totals for each column, and their grand total and average+--+-- It is used in compound balance report commands like balancesheet, +-- cashflow and incomestatement.+type CompoundBalanceReport = +  ( String+  , [(String, MultiBalanceReport)]+  , ([MixedAmount], MixedAmount, MixedAmount)+  ) +-- | Run one subreport for a compound balance command in multi-column mode.+-- This returns a MultiBalanceReport.+compoundBalanceSubreport :: ReportOpts -> Query -> Journal -> (Journal -> Query) -> Maybe NormalBalance -> MultiBalanceReport+compoundBalanceSubreport ropts userq j subreportqfn subreportnormalsign = r'+  where+    -- force --empty to ensure same columns in all sections+    ropts' = ropts { empty_=True, normalbalance_=subreportnormalsign }+    -- run the report+    q = And [subreportqfn j, userq]+    r@(MultiBalanceReport (dates, rows, totals)) = multiBalanceReport ropts' q j+    -- if user didn't specify --empty, now remove the all-zero rows+    r' | empty_ ropts = r+       | otherwise    = MultiBalanceReport (dates, rows', totals) +          where+            rows' = filter (not . emptyRow) rows+              where+                emptyRow (_,_,_,amts,_,_) = all isZeroMixedAmount amts++-- | Render a compound balance report as plain text suitable for console output.+{- Eg:+Balance Sheet++             ||  2017/12/31    Total  Average +=============++===============================+ Assets      ||                               +-------------++-------------------------------+ assets:b    ||           1        1        1 +-------------++-------------------------------+             ||           1        1        1 +=============++===============================+ Liabilities ||                               +-------------++-------------------------------+-------------++-------------------------------+             ||                               +=============++===============================+ Total       ||           1        1        1 ++-}+compoundBalanceReportAsText :: ReportOpts -> CompoundBalanceReport -> String+compoundBalanceReportAsText ropts (title, subreports, (coltotals, grandtotal, grandavg)) =+  title ++ "\n\n" ++ +  renderBalanceReportTable ropts bigtable'+  where+    singlesubreport = length subreports == 1+    bigtable = +      case map (subreportAsTable ropts singlesubreport) subreports of+        []   -> T.empty+        r:rs -> foldl' concatTables r rs+    bigtable'+      | no_total_ ropts || singlesubreport = +          bigtable+      | otherwise =+          bigtable+          +====++          row "Total" (+            coltotals+            ++ (if row_total_ ropts then [grandtotal] else [])+            ++ (if average_ ropts   then [grandavg]   else [])+            )++    -- | Convert a named multi balance report to a table suitable for+    -- concatenating with others to make a compound balance report table.+    subreportAsTable ropts singlesubreport (title, r) = t+      where+        -- unless there's only one section, always show the subtotal row+        ropts' | singlesubreport = ropts+               | otherwise       = ropts{ no_total_=False }+        -- convert to table+        Table lefthdrs tophdrs cells = balanceReportAsTable ropts' r+        -- tweak the layout+        t = Table (T.Group SingleLine [Header title, lefthdrs]) tophdrs ([]:cells)++-- | Add the second table below the first, discarding its column headings.+concatTables (Table hLeft hTop dat) (Table hLeft' _ dat') =+    Table (T.Group DoubleLine [hLeft, hLeft']) hTop (dat ++ dat')++-- | Render a compound balance report as CSV.+{- Eg: +ghci> :main -f examples/sample.journal bs -Y -O csv -AT+"Balance Sheet","","","","",""+"Assets","","","","",""+"account","short account","indent","2008","total","average"+"assets:bank:saving","saving","3","$1","$1","$1"+"assets:cash","cash","2","$-2","$-2","$-2"+"totals","","","$-1","$-1","$-1"+"Liabilities","","","","",""+"account","short account","indent","2008","total","average"+"liabilities:debts","debts","2","$1","$1","$1"+"totals","","","$1","$1","$1"+"Total","0","0","0"+-}+compoundBalanceReportAsCsv :: ReportOpts -> CompoundBalanceReport -> CSV+compoundBalanceReportAsCsv ropts (title, subreports, (coltotals, grandtotal, grandavg)) =+  addtotals $+  padRow title :+  concatMap (subreportAsCsv ropts singlesubreport) subreports+  where+    singlesubreport = length subreports == 1+    subreportAsCsv ropts singlesubreport (subreporttitle, multibalreport) =+      padRow subreporttitle :+      multiBalanceReportAsCsv ropts' multibalreport+      where+        -- unless there's only one section, always show the subtotal row+        ropts' | singlesubreport = ropts+               | otherwise       = ropts{ no_total_=False }+    padRow s = take numcols $ s : repeat ""+      where+        numcols+          | null subreports = 1+          | otherwise =+            (3 +) $ -- account name & indent columns+            (if row_total_ ropts then (1+) else id) $+            (if average_ ropts then (1+) else id) $+            maximum $ -- depends on non-null subreports+            map (\(MultiBalanceReport (amtcolheadings, _, _)) -> length amtcolheadings) $ +            map snd subreports+    addtotals+      | no_total_ ropts || length subreports == 1 = id+      | otherwise = (++ +          ["Total" :+           map showMixedAmountOneLineWithoutPrice (+             coltotals+             ++ (if row_total_ ropts then [grandtotal] else [])+             ++ (if average_ ropts   then [grandavg]   else [])+             )+          ])
Hledger/Cli/DocFiles.hs view
@@ -16,6 +16,7 @@   ,printHelpForTopic   ,runManForTopic   ,runInfoForTopic+  ,runPagerForTopic    ) where @@ -33,22 +34,22 @@  docFiles :: IsString a => [(Topic, (a, a, a))] docFiles = [-   ("cli",+   ("hledger",     ($(makeRelativeToProject "doc/hledger.1" >>= embedStringFile)     ,$(makeRelativeToProject "doc/hledger.1.txt" >>= embedStringFile)     ,$(makeRelativeToProject "doc/hledger.1.info" >>= embedStringFile)     ))-  ,("ui",+  ,("hledger-ui",     ($(makeRelativeToProject "doc/other/hledger-ui.1" >>= embedStringFile)     ,$(makeRelativeToProject "doc/other/hledger-ui.1.txt" >>= embedStringFile)     ,$(makeRelativeToProject "doc/other/hledger-ui.1.info" >>= embedStringFile)     ))-  ,("web",+  ,("hledger-web",     ($(makeRelativeToProject "doc/other/hledger-web.1" >>= embedStringFile)     ,$(makeRelativeToProject "doc/other/hledger-web.1.txt" >>= embedStringFile)     ,$(makeRelativeToProject "doc/other/hledger-web.1.info" >>= embedStringFile)     ))-  ,("api",+  ,("hledger-api",     ($(makeRelativeToProject "doc/other/hledger-api.1" >>= embedStringFile)     ,$(makeRelativeToProject "doc/other/hledger-api.1.txt" >>= embedStringFile)     ,$(makeRelativeToProject "doc/other/hledger-api.1.info" >>= embedStringFile)@@ -93,6 +94,15 @@ printHelpForTopic :: Topic -> IO () printHelpForTopic t =   putStrLn $ lookupDocTxt t++runPagerForTopic :: FilePath -> Topic -> IO ()+runPagerForTopic exe t = do+  (Just inp, _, _, ph) <- createProcess (proc exe []){+    std_in=CreatePipe+    }+  hPutStrLn inp (lookupDocTxt t)+  _ <- waitForProcess ph+  return ()  runManForTopic :: Topic -> IO () runManForTopic t =
− Hledger/Cli/Help.hs
@@ -1,42 +0,0 @@-{-|--The help command.--|-}--module Hledger.Cli.Help (--   helpmode-  ,help'--  ) where--import Prelude ()-import Prelude.Compat-import Data.List-import System.Console.CmdArgs.Explicit--import Hledger.Data.RawOptions-import Hledger.Cli.CliOptions-import Hledger.Cli.DocFiles--helpmode = (defCommandMode $ ["help"] ++ aliases) {-  modeHelp = "show any of the hledger manuals" `withAliases` aliases- ,modeGroupFlags = Group {-     groupUnnamed = []-    ,groupHidden = []-    ,groupNamed = []-    }- }-  where aliases = []---- | Print detailed help on various topics.-help' :: CliOpts -> IO ()-help' opts = do-  let args = listofstringopt "args" $ rawopts_ opts-  case args of-    []    -> putStrLn $-             "Choose a topic, eg: hledger help cli\n" ++-             intercalate ", " docTopics-    topic:_ -> printHelpForTopic topic-
− Hledger/Cli/Histogram.hs
@@ -1,59 +0,0 @@-{-|--Print a histogram report. (The "activity" command).---}--module Hledger.Cli.Histogram-where--import Data.List-import Data.Maybe-import Data.Ord-import System.Console.CmdArgs.Explicit-import Text.Printf--import Hledger-import Hledger.Cli.CliOptions-import Prelude hiding (putStr)-import Hledger.Utils.UTF8IOCompat (putStr)--activitymode :: Mode RawOpts-activitymode = (defCommandMode $ ["activity"] ++ aliases) {-  modeHelp = "show an ascii barchart of posting counts per interval (default: daily)" `withAliases` aliases- ,modeHelpSuffix = []- ,modeGroupFlags = Group {-     groupUnnamed = []-    ,groupHidden = []-    ,groupNamed = [generalflagsgroup1]-    }- }-  where aliases = []--barchar :: Char-barchar = '*'---- | Print a histogram of some statistic per report interval, such as--- number of postings per day.-histogram :: CliOpts -> Journal -> IO ()-histogram CliOpts{reportopts_=ropts} j = do-  d <- getCurrentDay-  putStr $ showHistogram ropts (queryFromOpts d ropts) j--showHistogram :: ReportOpts -> Query -> Journal -> String-showHistogram opts q j = concatMap (printDayWith countBar) spanps-    where-      i = interval_ opts-      interval | i == NoInterval = Days 1-               | otherwise = i-      span' = queryDateSpan (date2_ opts) q `spanDefaultsFrom` journalDateSpan (date2_ opts) j-      spans = filter (DateSpan Nothing Nothing /=) $ splitSpan interval span'-      spanps = [(s, filter (isPostingInDateSpan s) ps) | s <- spans]-      -- same as Register-      -- should count transactions, not postings ?-      -- ps = sortBy (comparing postingDate) $ filterempties $ filter matchapats $ filterdepth $ journalPostings j-      ps = sortBy (comparing postingDate) $ filter (q `matchesPosting`) $ journalPostings j--printDayWith f (DateSpan b _, ps) = printf "%s %s\n" (show $ fromJust b) (f ps)--countBar ps = replicate (length ps) barchar
− Hledger/Cli/Incomestatement.hs
@@ -1,47 +0,0 @@-{-# LANGUAGE QuasiQuotes, TemplateHaskell, OverloadedStrings, NoCPP #-}-{-|--The @incomestatement@ command prints a simple income statement (profit & loss report).---}--module Hledger.Cli.Incomestatement (-  incomestatementmode- ,incomestatement- ,tests_Hledger_Cli_Incomestatement-) where--import Data.String.Here-import System.Console.CmdArgs.Explicit-import Test.HUnit--import Hledger-import Hledger.Cli.CliOptions-import Hledger.Cli.CompoundBalanceCommand--incomestatementSpec = CompoundBalanceCommandSpec {-  cbcname     = "incomestatement",-  cbcaliases  = ["is"],-  cbchelp     = [here|-This command displays a simple income statement, showing revenues-and expenses during a period. It assumes that these accounts are under a -top-level `revenue` or `income` or `expense` account (case insensitive,-plural forms also allowed).-  |],-  cbctitle    = "Income Statement",-  cbcqueries  = [ ("Revenues", journalIncomeAccountQuery),-                 ("Expenses", journalExpenseAccountQuery)-               ],-  cbctype     = PeriodChange-}--incomestatementmode :: Mode RawOpts-incomestatementmode = compoundBalanceCommandMode incomestatementSpec--incomestatement :: CliOpts -> Journal -> IO ()-incomestatement = compoundBalanceCommand incomestatementSpec--tests_Hledger_Cli_Incomestatement :: Test-tests_Hledger_Cli_Incomestatement = TestList- [- ]
− Hledger/Cli/Info.hs
@@ -1,41 +0,0 @@-{-|--The info command.--|-}--module Hledger.Cli.Info (--   infomode-  ,info'--  ) where--import Prelude ()-import Prelude.Compat-import Data.List-import System.Console.CmdArgs.Explicit--import Hledger.Data.RawOptions-import Hledger.Cli.CliOptions-import Hledger.Cli.DocFiles--infomode = (defCommandMode $ ["info"] ++ aliases) {-  modeHelp = "show any of the hledger manuals with info" `withAliases` aliases- ,modeGroupFlags = Group {-     groupUnnamed = []-    ,groupHidden = []-    ,groupNamed = []-    }- }-  where aliases = []---- | Try to use info to view the selected manual.-info' :: CliOpts -> IO ()-info' opts = do-  let args = listofstringopt "args" $ rawopts_ opts-  case args of-    []    -> putStrLn $-             "Choose a topic, eg: hledger info cli\n" ++-             intercalate ", " docTopics-    topic:_ -> runInfoForTopic topic
Hledger/Cli/Main.hs view
@@ -40,11 +40,9 @@  module Hledger.Cli.Main where --- import Control.Monad import Data.Char (isDigit)-import Data.String.Here import Data.List-import Data.List.Split (splitOn)+import Data.String.Here import Safe import System.Console.CmdArgs.Explicit as C import System.Environment@@ -53,36 +51,14 @@ import System.Process import Text.Printf -import Hledger (ensureJournalFileExists)-import Hledger.Cli.Add-import Hledger.Cli.Accounts-import Hledger.Cli.Balance-import Hledger.Cli.Balancesheet-import Hledger.Cli.Cashflow-import Hledger.Cli.DocFiles-import Hledger.Cli.Help-import Hledger.Cli.Histogram-import Hledger.Cli.Incomestatement-import Hledger.Cli.Info-import Hledger.Cli.Man-import Hledger.Cli.Print-import Hledger.Cli.Register-import Hledger.Cli.Stats-import Hledger.Cli.CliOptions-import Hledger.Cli.Tests-import Hledger.Cli.Utils-import Hledger.Cli.Version-import Hledger.Data.Dates (getCurrentDay)-import Hledger.Data.RawOptions (RawOpts)-import Hledger.Reports.ReportOptions (period_, interval_, queryFromOpts)-import Hledger.Utils+import Hledger.Cli  --- | The overall cmdargs mode describing command-line options for hledger.+-- | The overall cmdargs mode describing hledger's command-line options and subcommands. mainmode addons = defMode {   modeNames = [progname ++ " [CMD]"]  ,modeArgs = ([], Just $ argsFlag "[ARGS]")- ,modeHelp = unlines ["hledger's command line interface"]+ ,modeHelp = unlines ["hledger's main command line interface. Runs builtin commands and other hledger executables. Type \"hledger\" to list available commands."]  ,modeGroupModes = Group {     -- subcommands in the unnamed group, shown first:     groupUnnamed = [@@ -91,23 +67,7 @@    ,groupNamed = [      ]     -- subcommands handled but not shown in the help:-   ,groupHidden = [-      oldconvertmode-     ,accountsmode-     ,activitymode-     ,addmode-     ,balancemode-     ,balancesheetmode-     ,cashflowmode-     ,helpmode-     ,incomestatementmode-     ,infomode-     ,manmode-     ,printmode-     ,registermode-     ,statsmode-     ,testmode-     ] ++ map quickAddonCommandMode addons+   ,groupHidden = map fst builtinCommands ++ map quickAddonCommandMode addons    }  ,modeGroupFlags = Group {      -- flags in named groups:@@ -127,178 +87,13 @@ PROGNAME                         list commands PROGNAME CMD [--] [OPTS] [ARGS]  run a command (use -- with addon commands) PROGNAME-CMD [OPTS] [ARGS]       or run addon commands directly-PROGNAME -h                      general usage-PROGNAME CMD -h                  command usage-PROGNAME --help                  PROGNAME manual-PROGNAME --man                   PROGNAME manual as man page-PROGNAME --info                  PROGNAME manual as info manual-PROGNAME help                    list help topics-PROGNAME help TOPIC              TOPIC manual-PROGNAME man  TOPIC              TOPIC manual as man page-PROGNAME info TOPIC              TOPIC manual as info manual+PROGNAME -h                      show general usage+PROGNAME CMD -h                  show command usage+PROGNAME help [MANUAL]           show any of the hledger manuals in various formats |]  } -oldconvertmode = (defCommandMode ["convert"]) {-  modeValue = [("command","convert")]- ,modeHelp = "convert is no longer needed, just use -f FILE.csv"- ,modeArgs = ([], Just $ argsFlag "[CSVFILE]")- ,modeGroupFlags = Group {-     groupUnnamed = []-    ,groupHidden = helpflags-    ,groupNamed = []-    }- }--builtinCommands :: [Mode RawOpts]-builtinCommands =-  let gs = modeGroupModes $ mainmode []-  in concatMap snd (groupNamed gs) ++ groupUnnamed gs ++ groupHidden gs--builtinCommandNames :: [String]-builtinCommandNames = concatMap modeNames builtinCommands---- | Parse hledger CLI options from these command line arguments and--- add-on command names, or raise any error.-argsToCliOpts :: [String] -> [String] -> IO CliOpts-argsToCliOpts args addons = do-  let-    args'        = moveFlagsAfterCommand args-    cmdargsopts  = either usageError id $ process (mainmode addons) args'-    cmdargsopts' = decodeRawOpts cmdargsopts-  rawOptsToCliOpts cmdargsopts'---- | A hacky workaround for cmdargs not accepting flags before the--- subcommand name: try to detect and move such flags after the--- command.  This allows the user to put them in either position.--- The order of options is not preserved, but this should be ok.------ Since we're not parsing flags as precisely as cmdargs here, this is--- imperfect. We make a decent effort to:--- - move all no-argument help/input/report flags--- - move all required-argument help/input/report flags along with their values, space-separated or not--- - not confuse things further or cause misleading errors.-moveFlagsAfterCommand :: [String] -> [String]-moveFlagsAfterCommand args = moveArgs $ ensureDebugHasArg args-  where-    -- quickly! make sure --debug has a numeric argument, or this all goes to hell-    ensureDebugHasArg as =-      case break (=="--debug") as of-       (bs,"--debug":c:cs) | null c || not (all isDigit c) -> bs++"--debug=1":c:cs-       (bs,"--debug":[])                                   -> bs++"--debug=1":[]-       _                                                   -> as--    -- -h ..., --version ...-    moveArgs (f:a:as)   | isMovableNoArgFlag f                   = (moveArgs $ a:as) ++ [f]-    -- -f FILE ..., --alias ALIAS ...-    moveArgs (f:v:a:as) | isMovableReqArgFlag f, isValue v       = (moveArgs $ a:as) ++ [f,v]-    -- -fFILE ..., --alias=ALIAS ...-    moveArgs (fv:a:as)  | isMovableReqArgFlagAndValue fv         = (moveArgs $ a:as) ++ [fv]-    -- -f(missing arg)-    moveArgs (f:a:as)   | isMovableReqArgFlag f, not (isValue a) = (moveArgs $ a:as) ++ [f]-    -- anything else-    moveArgs as = as--isMovableNoArgFlag a  = "-" `isPrefixOf` a && dropWhile (=='-') a `elem` noargflagstomove--isMovableReqArgFlag a = "-" `isPrefixOf` a && dropWhile (=='-') a `elem` reqargflagstomove--isMovableReqArgFlagAndValue ('-':'-':a:as) = case break (== '=') (a:as) of (f:fs,_:_) -> (f:fs) `elem` reqargflagstomove-                                                                           _          -> False-isMovableReqArgFlagAndValue ('-':shortflag:_:_) = [shortflag] `elem` reqargflagstomove-isMovableReqArgFlagAndValue _ = False--isValue "-"     = True-isValue ('-':_) = False-isValue _       = True--flagstomove = inputflags ++ reportflags ++ helpflags-noargflagstomove  = concatMap flagNames $ filter ((==FlagNone).flagInfo) flagstomove-reqargflagstomove = -- filter (/= "debug") $-                    concatMap flagNames $ filter ((==FlagReq ).flagInfo) flagstomove---- | Template for the commands list. Includes an entry for known (or--- hypothetical) builtin and addon commands; these will be filtered--- based on the commands found at runtime.  COUNT is replaced with the--- number of commands found.  OTHERCMDS is replaced with an entry for--- each unknown addon command found. The command descriptions here--- should be synced with the commands' builtin help and the command--- list in the hledger manual.-commandsListTemplate :: String-commandsListTemplate = [here|Commands available (COUNT):--Standard reports:- accounts             show chart of accounts- balancesheet (bs)    show a balance sheet- cashflow (cf)        show a cashflow statement- incomestatement (is) show an income statement- transactions (txns)  show transactions in some account--General reporting:- activity             show a bar chart of posting counts per interval- balance (bal)        show accounts and balances- budget               add automated postings/txns/bucket accts (experimental)- chart                generate simple balance pie charts (experimental)- check                check more powerful balance assertions- check-dates          check transactions are ordered by date- check-dupes          check for accounts with the same leaf name- irr                  calculate internal rate of return of an investment- prices               show market price records- print                show transaction journal entries- print-unique         show only transactions with unique descriptions- register (reg)       show postings and running total- register-match       show best matching transaction for a description- stats                show some journal statistics--Interfaces:- add                  console ui for adding transactions- api                  web api server- iadd                 curses ui for adding transactions- ui                   curses ui- web                  web ui--Misc:- autosync             download/deduplicate/convert OFX data- equity               generate transactions to zero & restore account balances- interest             generate interest transactions- rewrite              add automated postings to certain transactions- test                 run some self tests-OTHERCMDS-Help: (see also -h, CMD -h, --help|--man|--info)- help|man|info        show any of the hledger manuals in text/man/info format-|]--knownCommands :: [String]-knownCommands = sort $ commandsFromCommandsList commandsListTemplate---- | Extract the command names from a commands list like the above:--- the first word (or words separated by |) of lines beginning with a space.-commandsFromCommandsList :: String -> [String]-commandsFromCommandsList s = concatMap (splitOn "|") [w | ' ':l <- lines s, let w:_ = words l]---- | Print the commands list, modifying the template above based on--- the currently available addons. Missing addons will be removed, and--- extra addons will be added under Misc.-printCommandsList :: [String] -> IO ()-printCommandsList addonsFound = putStr commandsList-  where-    commandsFound = builtinCommandNames ++ addonsFound-    unknownCommandsFound = addonsFound \\ knownCommands--    adjustline (' ':l) | not $ w `elem` commandsFound = []-      where w = takeWhile (not . (`elem` "| ")) l-    adjustline l = [l]--    commandsList1 =-      regexReplace "OTHERCMDS" (unlines [' ':w | w <- unknownCommandsFound]) $-      unlines $ concatMap adjustline $ lines commandsListTemplate--    commandsList =-      regexReplace "COUNT" (show $ length $ commandsFromCommandsList commandsList1)-      commandsList1----- | Let's go.+-- | Let's go! main :: IO () main = do @@ -310,9 +105,9 @@   -- command-line.test.    -- some preliminary (imperfect) argument parsing to supplement cmdargs-  args <- getArgs+  args <- getArgs >>= expandArgsAt   let-    args'                = moveFlagsAfterCommand args+    args'                = moveFlagsAfterCommand $ replaceNumericFlags args     isFlag               = ("-" `isPrefixOf`)     isNonEmptyNonFlag s  = not (isFlag s) && not (null s)     rawcmd               = headDef "" $ takeWhile isNonEmptyNonFlag args'@@ -346,18 +141,10 @@     hasDetailedVersion   = ("--version+" `elem`)     printUsage           = putStr $ showModeUsage $ mainmode addons     badCommandError      = error' ("command "++rawcmd++" is not recognized, run with no command to see a list") >> exitFailure-    hasShortHelpFlag args = any (`elem` args) ["-h"]-    hasLongHelpFlag args = any (`elem` args) ["--help"]-    hasManFlag args      = any (`elem` args) ["--man"]-    hasInfoFlag args     = any (`elem` args) ["--info"]-    hasSomeHelpFlag args = hasShortHelpFlag args || hasLongHelpFlag args || hasManFlag args || hasInfoFlag args+    hasHelpFlag args     = any (`elem` args) ["-h","--help"]     f `orShowHelp` mode-      | hasShortHelpFlag args = putStr $ showModeUsage mode-      | hasLongHelpFlag args  = printHelpForTopic t-      | hasManFlag args       = runManForTopic t-      | hasInfoFlag args      = runInfoForTopic t-      | otherwise             = f-      where t = topicForMode mode+      | hasHelpFlag args = putStr $ showModeUsage mode+      | otherwise        = f   dbgIO "processed opts" opts   dbgIO "command matched" cmd   dbgIO "isNullCommand" isNullCommand@@ -371,36 +158,27 @@   let     runHledgerCommand       -- high priority flags and situations. -h, then --help, then --info are highest priority.-      | hasShortHelpFlag argsbeforecmd = dbgIO "" "-h before command, showing general usage" >> printUsage-      | hasLongHelpFlag  argsbeforecmd = dbgIO "" "--help before command, showing general manual" >> printHelpForTopic (topicForMode $ mainmode addons)-      | hasManFlag       argsbeforecmd = dbgIO "" "--man before command, showing general manual with man" >> runManForTopic (topicForMode $ mainmode addons)-      | hasInfoFlag      argsbeforecmd = dbgIO "" "--info before command, showing general manual with info" >> runInfoForTopic (topicForMode $ mainmode addons)-      | not (hasSomeHelpFlag argsaftercmd) && (hasVersion argsbeforecmd || (hasVersion argsaftercmd && isInternalCommand))+      | hasHelpFlag argsbeforecmd = dbgIO "" "-h before command, showing general usage" >> printUsage+      | not (hasHelpFlag argsaftercmd) && (hasVersion argsbeforecmd || (hasVersion argsaftercmd && isInternalCommand))                                  = putStrLn prognameandversion-      | not (hasSomeHelpFlag argsaftercmd) && (hasDetailedVersion argsbeforecmd || (hasDetailedVersion argsaftercmd && isInternalCommand))+      | not (hasHelpFlag argsaftercmd) && (hasDetailedVersion argsbeforecmd || (hasDetailedVersion argsaftercmd && isInternalCommand))                                  = putStrLn prognameanddetailedversion       -- \| (null externalcmd) && "binary-filename" `inRawOpts` rawopts = putStrLn $ binaryfilename progname       -- \| "--browse-args" `elem` args     = System.Console.CmdArgs.Helper.execute "cmdargs-browser" mainmode' args >>= (putStr . show)       | isNullCommand            = dbgIO "" "no command, showing commands list" >> printCommandsList addons       | isBadCommand             = badCommandError -      -- internal commands-      | cmd == "activity"        = withJournalDo opts histogram       `orShowHelp` activitymode-      | cmd == "add"             = (journalFilePathFromOpts opts >>= (ensureJournalFileExists . head) >> withJournalDo opts add) `orShowHelp` addmode-      | cmd == "accounts"        = withJournalDo opts accounts        `orShowHelp` accountsmode-      | cmd == "balance"         = withJournalDo opts balance         `orShowHelp` balancemode-      | cmd == "balancesheet"    = withJournalDo opts balancesheet    `orShowHelp` balancesheetmode-      | cmd == "cashflow"        = withJournalDo opts cashflow        `orShowHelp` cashflowmode-      | cmd == "incomestatement" = withJournalDo opts incomestatement `orShowHelp` incomestatementmode-      | cmd == "print"           = withJournalDo opts print'          `orShowHelp` printmode-      | cmd == "register"        = withJournalDo opts register        `orShowHelp` registermode-      | cmd == "stats"           = withJournalDo opts stats           `orShowHelp` statsmode-      | cmd == "test"            = test' opts                         `orShowHelp` testmode-      | cmd == "help"            = help' opts                         `orShowHelp` helpmode-      | cmd == "man"             = man opts                           `orShowHelp` manmode-      | cmd == "info"            = info' opts                         `orShowHelp` infomode+      -- builtin commands+      | Just (cmdmode, cmdaction) <- findCommand cmd = do +        if cmd=="add" -- add command does extra work before reading journal+        then (do+          journalFilePathFromOpts opts >>= (ensureJournalFileExists . head) +          withJournalDo opts cmdaction)+          `orShowHelp` cmdmode+        else+          withJournalDo opts cmdaction `orShowHelp` cmdmode -      -- an external command+      -- addon commands       | isExternalCommand = do           let externalargs = argsbeforecmd ++ filter (not.(=="--")) argsaftercmd           let shellcmd = printf "%s-%s %s" progname cmd (unwords' externalargs) :: String@@ -410,20 +188,69 @@           system shellcmd >>= exitWith        -- deprecated commands-      | cmd == "convert"         = error' (modeHelp oldconvertmode) >> exitFailure+      -- cmd == "convert"         = error' (modeHelp oldconvertmode) >> exitFailure        -- shouldn't reach here       | otherwise                = usageError ("could not understand the arguments "++show args) >> exitFailure    runHledgerCommand +-- | Parse hledger CLI options from these command line arguments and+-- add-on command names, or raise any error.+argsToCliOpts :: [String] -> [String] -> IO CliOpts+argsToCliOpts args addons = do+  let+    args'        = moveFlagsAfterCommand $ replaceNumericFlags args+    cmdargsopts  = either usageError id $ process (mainmode addons) args'+    cmdargsopts' = decodeRawOpts cmdargsopts+  rawOptsToCliOpts cmdargsopts' --- tests_runHledgerCommand = [---   -- "runHledgerCommand" ~: do---   --   let opts = defreportopts{query_="expenses"}---   --   d <- getCurrentDay---   --   runHledgerCommand addons opts@CliOpts{command_=cmd} args+-- | A hacky workaround for cmdargs not accepting flags before the+-- subcommand name: try to detect and move such flags after the+-- command.  This allows the user to put them in either position.+-- The order of options is not preserved, but this should be ok.+--+-- Since we're not parsing flags as precisely as cmdargs here, this is+-- imperfect. We make a decent effort to:+-- - move all no-argument help/input/report flags+-- - move all required-argument help/input/report flags along with their values, space-separated or not+-- - not confuse things further or cause misleading errors.+moveFlagsAfterCommand :: [String] -> [String]+moveFlagsAfterCommand args = moveArgs $ ensureDebugHasArg args+  where+    -- quickly! make sure --debug has a numeric argument, or this all goes to hell+    ensureDebugHasArg as =+      case break (=="--debug") as of+       (bs,"--debug":c:cs) | null c || not (all isDigit c) -> bs++"--debug=1":c:cs+       (bs,"--debug":[])                                   -> bs++"--debug=1":[]+       _                                                   -> as ---  ]+    -- -h ..., --version ...+    moveArgs (f:a:as)   | isMovableNoArgFlag f                   = (moveArgs $ a:as) ++ [f]+    -- -f FILE ..., --alias ALIAS ...+    moveArgs (f:v:a:as) | isMovableReqArgFlag f, isValue v       = (moveArgs $ a:as) ++ [f,v]+    -- -fFILE ..., --alias=ALIAS ...+    moveArgs (fv:a:as)  | isMovableReqArgFlagAndValue fv         = (moveArgs $ a:as) ++ [fv]+    -- -f(missing arg)+    moveArgs (f:a:as)   | isMovableReqArgFlag f, not (isValue a) = (moveArgs $ a:as) ++ [f]+    -- anything else+    moveArgs as = as +isMovableNoArgFlag a  = "-" `isPrefixOf` a && dropWhile (=='-') a `elem` noargflagstomove++isMovableReqArgFlag a = "-" `isPrefixOf` a && dropWhile (=='-') a `elem` reqargflagstomove++isMovableReqArgFlagAndValue ('-':'-':a:as) = case break (== '=') (a:as) of (f:fs,_:_) -> (f:fs) `elem` reqargflagstomove+                                                                           _          -> False+isMovableReqArgFlagAndValue ('-':shortflag:_:_) = [shortflag] `elem` reqargflagstomove+isMovableReqArgFlagAndValue _ = False++isValue "-"     = True+isValue ('-':_) = False+isValue _       = True++flagstomove = inputflags ++ reportflags ++ helpflags+noargflagstomove  = concatMap flagNames $ filter ((==FlagNone).flagInfo) flagstomove+reqargflagstomove = -- filter (/= "debug") $+                    concatMap flagNames $ filter ((==FlagReq ).flagInfo) flagstomove 
− Hledger/Cli/Man.hs
@@ -1,41 +0,0 @@-{-|--The man command.--|-}--module Hledger.Cli.Man (--   manmode-  ,man--  ) where--import Prelude ()-import Prelude.Compat-import Data.List-import System.Console.CmdArgs.Explicit--import Hledger.Data.RawOptions-import Hledger.Cli.CliOptions-import Hledger.Cli.DocFiles--manmode = (defCommandMode $ ["man"] ++ aliases) {-  modeHelp = "show any of the hledger manuals with man" `withAliases` aliases- ,modeGroupFlags = Group {-     groupUnnamed = []-    ,groupHidden = []-    ,groupNamed = []-    }- }-  where aliases = []---- | Try to use man to view the selected manual.-man :: CliOpts -> IO ()-man opts = do-  let args = listofstringopt "args" $ rawopts_ opts-  case args of-    []    -> putStrLn $-             "Choose a topic, eg: hledger man cli\n" ++-             intercalate ", " docTopics-    topic:_ -> runManForTopic topic
− Hledger/Cli/Print.hs
@@ -1,180 +0,0 @@-{-|--A ledger-compatible @print@ command.---}--{-# LANGUAGE OverloadedStrings #-}--module Hledger.Cli.Print (-  printmode- ,print'- -- ,entriesReportAsText- ,originalTransaction- ,tests_Hledger_Cli_Print-)-where--import Data.Text (Text)-import qualified Data.Text as T-import System.Console.CmdArgs.Explicit-import Test.HUnit-import Text.CSV--import Hledger-import Hledger.Cli.CliOptions-import Hledger.Cli.Utils-import Hledger.Cli.Add ( transactionsSimilarTo )---printmode = (defCommandMode $ ["print"] ++ aliases) {-  modeHelp = "show transaction journal entries" `withAliases` aliases- ,modeGroupFlags = Group {-     groupUnnamed = [-        let matcharg = "STR"-        in-         flagReq  ["match","m"] (\s opts -> Right $ setopt "match" s opts) matcharg-         ("show the transaction whose description is most similar to "++matcharg-          ++ ", and is most recent"),-        flagNone ["explicit","x"] (setboolopt "explicit")-         "show all amounts explicitly"-        ]-        ++ outputflags-    ,groupHidden = []-    ,groupNamed = [generalflagsgroup1]-    }- }-  where aliases = []---- | Print journal transactions in standard format.-print' :: CliOpts -> Journal -> IO ()-print' opts j = do-  case maybestringopt "match" $ rawopts_ opts of-    Nothing   -> printEntries opts j-    Just desc -> printMatch opts j $ T.pack desc--printEntries :: CliOpts -> Journal -> IO ()-printEntries opts@CliOpts{reportopts_=ropts} j = do-  d <- getCurrentDay-  let q = queryFromOpts d ropts-      fmt = outputFormatFromOpts opts-      (render, ropts') = case fmt of-        "csv" -> ((++"\n") . printCSV . entriesReportAsCsv, ropts{accountlistmode_=ALFlat})-        _     -> (entriesReportAsText opts,                 ropts)-  writeOutput opts $ render $ entriesReport ropts' q j--entriesReportAsText :: CliOpts -> EntriesReport -> String-entriesReportAsText opts = concatMap (showTransactionUnelided . gettxn) -  where-    gettxn | boolopt "explicit" $ rawopts_ opts = id                   -- use the fully inferred/explicit txn-           | otherwise                          = originalTransaction  -- use the original txn (more or less)---- Replace this transaction's postings with the original postings if any, but keep the--- current possibly rewritten account names.-originalTransaction t = t { tpostings = map originalPostingPreservingAccount $ tpostings t }---- Get the original posting if any, but keep the current possibly rewritten account name.-originalPostingPreservingAccount p = (originalPosting p) { paccount = paccount p }---- XXX--- tests_showTransactions = [---   "showTransactions" ~: do----    -- "print expenses" ~:---    do---     let opts = defreportopts{query_="expenses"}---     d <- getCurrentDay---     showTransactions opts (queryFromOpts d opts) samplejournal `is` unlines---      ["2008/06/03 * eat & shop"---      ,"    expenses:food                $1"---      ,"    expenses:supplies            $1"---      ,"    assets:cash                 $-2"---      ,""---      ]----   -- , "print report with depth arg" ~:---    do---     let opts = defreportopts{depth_=Just 2}---     d <- getCurrentDay---     showTransactions opts (queryFromOpts d opts) samplejournal `is` unlines---       ["2008/01/01 income"---       ,"    assets:bank:checking            $1"---       ,"    income:salary                  $-1"---       ,""---       ,"2008/06/01 gift"---       ,"    assets:bank:checking            $1"---       ,"    income:gifts                   $-1"---       ,""---       ,"2008/06/03 * eat & shop"---       ,"    expenses:food                $1"---       ,"    expenses:supplies            $1"---       ,"    assets:cash                 $-2"---       ,""---       ,"2008/12/31 * pay off"---       ,"    liabilities:debts               $1"---       ,"    assets:bank:checking           $-1"---       ,""---       ]---  ]--entriesReportAsCsv :: EntriesReport -> CSV-entriesReportAsCsv txns =-  ["txnidx","date","date2","status","code","description","comment","account","amount","commodity","credit","debit","posting-status","posting-comment"] :-  concatMap transactionToCSV txns---- | Generate one CSV record per posting, duplicating the common transaction fields.--- The txnidx field (transaction index) allows postings to be grouped back into transactions.-transactionToCSV :: Transaction -> CSV-transactionToCSV t =-  map (\p -> show idx:date:date2:status:code:description:comment:p)-   (concatMap postingToCSV $ tpostings t)-  where-    idx = tindex t-    description = T.unpack $ tdescription t-    date = showDate (tdate t)-    date2 = maybe "" showDate (tdate2 t)-    status = show $ tstatus t-    code = T.unpack $ tcode t-    comment = chomp $ strip $ T.unpack $ tcomment t--postingToCSV :: Posting -> CSV-postingToCSV p =-  map (\(a@(Amount {aquantity=q,acommodity=c})) ->-    let a_ = a{acommodity=""} in-    let amount = showAmount a_ in-    let commodity = T.unpack c in-    let credit = if q < 0 then showAmount $ negate a_ else "" in-    let debit  = if q >= 0 then showAmount a_ else "" in-    account:amount:commodity:credit:debit:status:comment:[])-   amounts-  where-    Mixed amounts = pamount p-    status = show $ pstatus p-    account = showAccountName Nothing (ptype p) (paccount p)-    comment = chomp $ strip $ T.unpack $ pcomment p---- --match---- | Print the transaction most closely and recently matching a description--- (and the query, if any).-printMatch :: CliOpts -> Journal -> Text -> IO ()-printMatch CliOpts{reportopts_=ropts} j desc = do-  d <- getCurrentDay-  let q = queryFromOpts d ropts-  case similarTransaction' j q desc of-                Nothing -> putStrLn "no matches found."-                Just t  -> putStr $ showTransactionUnelided t--  where-    -- Identify the closest recent match for this description in past transactions.-    similarTransaction' :: Journal -> Query -> Text -> Maybe Transaction-    similarTransaction' j q desc-      | null historymatches = Nothing-      | otherwise           = Just $ snd $ head historymatches-      where-        historymatches = transactionsSimilarTo j q desc---- tests--tests_Hledger_Cli_Print = TestList []-  -- tests_showTransactions
− Hledger/Cli/Register.hs
@@ -1,204 +0,0 @@-{-|--A ledger-compatible @register@ command.---}--{-# LANGUAGE CPP, OverloadedStrings #-}--module Hledger.Cli.Register (-  registermode- ,register- ,postingsReportAsText- ,postingsReportItemAsText- -- ,showPostingWithBalanceForVty- ,tests_Hledger_Cli_Register-) where--import Data.List-import Data.Maybe--- import Data.Text (Text)-import qualified Data.Text as T-import System.Console.CmdArgs.Explicit-import Text.CSV-import Test.HUnit--import Hledger-import Hledger.Cli.CliOptions-import Hledger.Cli.Utils---registermode = (defCommandMode $ ["register"] ++ aliases) {-  modeHelp = "show postings and running total" `withAliases` aliases- ,modeGroupFlags = Group {-     groupUnnamed = [-      flagNone ["cumulative"]         (\opts -> setboolopt "change" opts)-        "show running total from report start date (default)"-     ,flagNone ["historical","H"] (\opts -> setboolopt "historical" opts)-        "show historical running total/balance (includes postings before report start date)\n "-     ,flagNone ["average","A"] (\opts -> setboolopt "average" opts)-        "show running average of posting amounts instead of total (implies --empty)"-     ,flagNone ["related","r"] (\opts -> setboolopt "related" opts) "show postings' siblings instead"-     ,flagReq  ["width","w"] (\s opts -> Right $ setopt "width" s opts) "N"-      ("set output width (default: " ++-#ifdef mingw32_HOST_OS-       show defaultWidth-#else-       "terminal width"-#endif-       ++ " or $COLUMNS). -wN,M sets description width as well."-       )-    ]-     ++ outputflags-    ,groupHidden = []-    ,groupNamed = [generalflagsgroup1]-    }- }-  where aliases = ["reg"]---- | Print a (posting) register report.-register :: CliOpts -> Journal -> IO ()-register opts@CliOpts{reportopts_=ropts} j = do-  d <- getCurrentDay-  let fmt = outputFormatFromOpts opts-      render | fmt=="csv" = const ((++"\n") . printCSV . postingsReportAsCsv)-             | otherwise  = postingsReportAsText-  writeOutput opts $ render opts $ postingsReport ropts (queryFromOpts d ropts) j--postingsReportAsCsv :: PostingsReport -> CSV-postingsReportAsCsv (_,is) =-  ["txnidx","date","description","account","amount","total"]-  :-  map postingsReportItemAsCsvRecord is--postingsReportItemAsCsvRecord :: PostingsReportItem -> Record-postingsReportItemAsCsvRecord (_, _, _, p, b) = [idx,date,desc,acct,amt,bal]-  where-    idx  = show $ maybe 0 tindex $ ptransaction p-    date = showDate $ postingDate p -- XXX csv should show date2 with --date2-    desc = T.unpack $ maybe "" tdescription $ ptransaction p-    acct = bracket $ T.unpack $ paccount p-      where-        bracket = case ptype p of-                             BalancedVirtualPosting -> (\s -> "["++s++"]")-                             VirtualPosting -> (\s -> "("++s++")")-                             _ -> id-    amt = showMixedAmountOneLineWithoutPrice $ pamount p-    bal = showMixedAmountOneLineWithoutPrice b---- | Render a register report as plain text suitable for console output.-postingsReportAsText :: CliOpts -> PostingsReport -> String-postingsReportAsText opts (_,items) = unlines $ map (postingsReportItemAsText opts amtwidth balwidth) items-  where-    amtwidth = maximumStrict $ 12 : map (strWidth . showMixedAmount . itemamt) items-    balwidth = maximumStrict $ 12 : map (strWidth . showMixedAmount . itembal) items-    itemamt (_,_,_,Posting{pamount=a},_) = a-    itembal (_,_,_,_,a) = a--tests_postingsReportAsText = [-  "postingsReportAsText" ~: do-  -- "unicode in register layout" ~: do-    j <- readJournal'-      "2009/01/01 * медвежья шкура\n  расходы:покупки  100\n  актив:наличные\n"-    let opts = defreportopts-    (postingsReportAsText defcliopts $ postingsReport opts (queryFromOpts (parsedate "2008/11/26") opts) j) `is` unlines-      ["2009/01/01 медвежья шкура       расходы:покупки                100           100"-      ,"                                актив:наличные                -100             0"]- ]---- | Render one register report line item as plain text. Layout is like so:--- @--- <---------------- width (specified, terminal width, or 80) -------------------->--- date (10)  description           account              amount (12)   balance (12)--- DDDDDDDDDD dddddddddddddddddddd  aaaaaaaaaaaaaaaaaaa  AAAAAAAAAAAA  AAAAAAAAAAAA--- @--- If description's width is specified, account will use the remaining space.--- Otherwise, description and account divide up the space equally.------ With a report interval, the layout is like so:--- @--- <---------------- width (specified, terminal width, or 80) -------------------->--- date (21)              account                        amount (12)   balance (12)--- DDDDDDDDDDDDDDDDDDDDD  aaaaaaaaaaaaaaaaaaaaaaaaaaaaa  AAAAAAAAAAAA  AAAAAAAAAAAA--- @------ date and description are shown for the first posting of a transaction only.------ Returns a string which can be multi-line, eg if the running balance--- has multiple commodities. Does not yet support formatting control--- like balance reports.----postingsReportItemAsText :: CliOpts -> Int -> Int -> PostingsReportItem -> String-postingsReportItemAsText opts preferredamtwidth preferredbalwidth (mdate, menddate, mdesc, p, b) =-  -- use elide*Width to be wide-char-aware-  -- trace (show (totalwidth, datewidth, descwidth, acctwidth, amtwidth, balwidth)) $-  intercalate "\n" $-    [concat [fitString (Just datewidth) (Just datewidth) True True date-            ," "-            ,fitString (Just descwidth) (Just descwidth) True True desc-            ,"  "-            ,fitString (Just acctwidth) (Just acctwidth) True True acct-            ,"  "-            ,fitString (Just amtwidth) (Just amtwidth) True False amtfirstline-            ,"  "-            ,fitString (Just balwidth) (Just balwidth) True False balfirstline-            ]]-    ++-    [concat [spacer-            ,fitString (Just amtwidth) (Just amtwidth) True False a-            ,"  "-            ,fitString (Just balwidth) (Just balwidth) True False b-            ]-     | (a,b) <- zip amtrest balrest-     ]-    where-      -- calculate widths-      (totalwidth,mdescwidth) = registerWidthsFromOpts opts-      (datewidth, date) = case (mdate,menddate) of-                            (Just _, Just _)   -> (21, showDateSpan (DateSpan mdate menddate))-                            (Nothing, Just _)  -> (21, "")-                            (Just d, Nothing)  -> (10, showDate d)-                            _                  -> (10, "")-      (amtwidth, balwidth)-        | shortfall <= 0 = (preferredamtwidth, preferredbalwidth)-        | otherwise      = (adjustedamtwidth, adjustedbalwidth)-        where-          mincolwidth = 2 -- columns always show at least an ellipsis-          maxamtswidth = max 0 (totalwidth - (datewidth + 1 + mincolwidth + 2 + mincolwidth + 2 + 2))-          shortfall = (preferredamtwidth + preferredbalwidth) - maxamtswidth-          amtwidthproportion = fromIntegral preferredamtwidth / fromIntegral (preferredamtwidth + preferredbalwidth)-          adjustedamtwidth = round $ amtwidthproportion * fromIntegral maxamtswidth-          adjustedbalwidth = maxamtswidth - adjustedamtwidth--      remaining = totalwidth - (datewidth + 1 + 2 + amtwidth + 2 + balwidth)-      (descwidth, acctwidth)-        | hasinterval = (0, remaining - 2)-        | otherwise   = (w, remaining - 2 - w)-        where-            hasinterval = isJust menddate-            w = fromMaybe ((remaining - 2) `div` 2) mdescwidth--      -- gather content-      desc = fromMaybe "" mdesc-      acct = parenthesise $ T.unpack $ elideAccountName awidth $ paccount p-         where-          (parenthesise, awidth) =-            case ptype p of-              BalancedVirtualPosting -> (\s -> "["++s++"]", acctwidth-2)-              VirtualPosting         -> (\s -> "("++s++")", acctwidth-2)-              _                      -> (id,acctwidth)-      amt = showMixedAmountWithoutPrice $ pamount p-      bal = showMixedAmountWithoutPrice b-      -- alternate behaviour, show null amounts as 0 instead of blank-      -- amt = if null amt' then "0" else amt'-      -- bal = if null bal' then "0" else bal'-      (amtlines, ballines) = (lines amt, lines bal)-      (amtlen, ballen) = (length amtlines, length ballines)-      numlines = max 1 (max amtlen ballen)-      (amtfirstline:amtrest) = take numlines $ amtlines ++ repeat "" -- posting amount is top-aligned-      (balfirstline:balrest) = take numlines $ replicate (numlines - ballen) "" ++ ballines -- balance amount is bottom-aligned-      spacer = replicate (totalwidth - (amtwidth + 2 + balwidth)) ' '--tests_Hledger_Cli_Register :: Test-tests_Hledger_Cli_Register = TestList-  tests_postingsReportAsText
− Hledger/Cli/Stats.hs
@@ -1,112 +0,0 @@-{-|--Print some statistics for the journal.---}--{-# LANGUAGE OverloadedStrings #-}--module Hledger.Cli.Stats (-  statsmode- ,stats-)-where--import Data.List-import Data.Maybe-import Data.Ord-import Data.HashSet (size, fromList)--- import Data.Text (Text)-import qualified Data.Text as T-import Data.Time.Calendar-import System.Console.CmdArgs.Explicit-import Text.Printf-import qualified Data.Map as Map--import Hledger-import Hledger.Cli.CliOptions-import Prelude hiding (putStr)-import Hledger.Cli.Utils (writeOutput)---statsmode = (defCommandMode $ ["stats"] ++ aliases) {-  modeHelp = "show some journal statistics" `withAliases` aliases- ,modeGroupFlags = Group {-     groupUnnamed = [-        flagReq  ["output-file","o"]   (\s opts -> Right $ setopt "output-file" s opts) "FILE" "write output to FILE.  A file extension matching one of the above formats selects that format."-        ]-    ,groupHidden = []-    ,groupNamed = [generalflagsgroup1]-    }- }-  where aliases = []---- like Register.summarisePostings--- | Print various statistics for the journal.-stats :: CliOpts -> Journal -> IO ()-stats opts@CliOpts{reportopts_=reportopts_} j = do-  d <- getCurrentDay-  let q = queryFromOpts d reportopts_-      l = ledgerFromJournal q j-      reportspan = (ledgerDateSpan l) `spanDefaultsFrom` (queryDateSpan False q)-      intervalspans = splitSpan (interval_ reportopts_) reportspan-      showstats = showLedgerStats l d-      s = intercalate "\n" $ map showstats intervalspans-  writeOutput opts s--showLedgerStats :: Ledger -> Day -> DateSpan -> String-showLedgerStats l today span =-    unlines $ map (\(label,value) -> concatBottomPadded [printf fmt1 label, value]) stats-    where-      fmt1 = "%-" ++ show w1 ++ "s: "-      -- fmt2 = "%-" ++ show w2 ++ "s"-      w1 = maximum $ map (length . fst) stats-      -- w2 = maximum $ map (length . show . snd) stats-      stats = [-         ("Main file" :: String, path) -- ++ " (from " ++ source ++ ")")-        ,("Included files", unlines $ drop 1 $ journalFilePaths j)-        ,("Transactions span", printf "%s to %s (%d days)" (start span) (end span) days)-        ,("Last transaction", maybe "none" show lastdate ++ showelapsed lastelapsed)-        ,("Transactions", printf "%d (%0.1f per day)" tnum txnrate)-        ,("Transactions last 30 days", printf "%d (%0.1f per day)" tnum30 txnrate30)-        ,("Transactions last 7 days", printf "%d (%0.1f per day)" tnum7 txnrate7)-        ,("Payees/descriptions", show $ size $ fromList $ map (tdescription) ts)-        ,("Accounts", printf "%d (depth %d)" acctnum acctdepth)-        ,("Commodities", printf "%s (%s)" (show $ length cs) (T.intercalate ", " cs))-      -- Transactions this month     : %(monthtxns)s (last month in the same period: %(lastmonthtxns)s)-      -- Unmarked transactions      : %(unmarked)s-      -- Days since reconciliation   : %(reconcileelapsed)s-      -- Days since last transaction : %(recentelapsed)s-       ]-           where-             j = ljournal l-             path = journalFilePath j-             ts = sortBy (comparing tdate) $ filter (spanContainsDate span . tdate) $ jtxns j-             as = nub $ map paccount $ concatMap tpostings ts-             cs = Map.keys $ commodityStylesFromAmounts $ concatMap amounts $ map pamount $ concatMap tpostings ts-             lastdate | null ts = Nothing-                      | otherwise = Just $ tdate $ last ts-             lastelapsed = maybe Nothing (Just . diffDays today) lastdate-             showelapsed Nothing = ""-             showelapsed (Just days) = printf " (%d %s)" days' direction-                                       where days' = abs days-                                             direction | days >= 0 = "days ago" :: String-                                                       | otherwise = "days from now"-             tnum = length ts-             start (DateSpan (Just d) _) = show d-             start _ = ""-             end (DateSpan _ (Just d)) = show d-             end _ = ""-             days = fromMaybe 0 $ daysInSpan span-             txnrate | days==0 = 0-                     | otherwise = fromIntegral tnum / fromIntegral days :: Double-             tnum30 = length $ filter withinlast30 ts-             withinlast30 t = d >= addDays (-30) today && (d<=today) where d = tdate t-             txnrate30 = fromIntegral tnum30 / 30 :: Double-             tnum7 = length $ filter withinlast7 ts-             withinlast7 t = d >= addDays (-7) today && (d<=today) where d = tdate t-             txnrate7 = fromIntegral tnum7 / 7 :: Double-             acctnum = length as-             acctdepth | null as = 0-                       | otherwise = maximum $ map accountNameLevel as-
− Hledger/Cli/Tests.hs
@@ -1,71 +0,0 @@--- {-# OPTIONS_GHC -F -pgmF htfpp #-}-{-# LANGUAGE CPP #-}-{- |--A simple test runner for hledger's built-in unit tests.---}--module Hledger.Cli.Tests (-  testmode- ,test'-)-where--import Control.Monad--- import Data.Text (Text)-import qualified Data.Text as T-import System.Exit-import Test.HUnit--import Hledger-import Hledger.Cli--#ifdef TESTS--import Test.Framework-import {-@ HTF_TESTS @-} Hledger.Read.JournalReader---- | Run HTF unit tests and exit with success or failure.-test' :: CliOpts -> IO ()-test' _opts = htfMain htf_importedTests--#else---- | Run HUnit unit tests and exit with success or failure.-test' :: CliOpts -> IO ()-test' opts = do-  results <- runTests opts-  if errors results > 0 || failures results > 0-   then exitFailure-   else exitWith ExitSuccess--testmode = (defCommandMode ["test"]) {-  modeHelp = "run built-in self-tests"- ,modeArgs = ([], Just $ argsFlag "[REGEXPS]")- ,modeGroupFlags = Group {-     groupUnnamed = []-    ,groupHidden = []-    ,groupNamed = [generalflagsgroup3]-    }- }---- | Run all or just the matched unit tests and return their HUnit result counts.-runTests :: CliOpts -> IO Counts-runTests = liftM (fst . flip (,) 0) . runTestTT . flatTests---- -- | Run all or just the matched unit tests until the first failure or--- -- error, returning the name of the problem test if any.--- runTestsTillFailure :: CliOpts -> IO (Maybe String)--- runTestsTillFailure _ = undefined -- do---   -- let ts = flatTests opts---   --     results = liftM (fst . flip (,) 0) $ runTestTT $---   --     firstproblem = find (\counts -> )---- | All or pattern-matched tests, as a flat list to show simple names.-flatTests opts = TestList $ filter (matchesAccount (queryFromOpts nulldate $ reportopts_ opts) . T.pack . testName) $ flattenTests tests_Hledger_Cli---- -- | All or pattern-matched tests, in the original suites to show hierarchical names.--- hierarchicalTests opts = filterTests (matchesAccount (queryFromOpts nulldate $ reportopts_ opts) . testName) tests_Hledger_Cli--#endif
Hledger/Cli/Utils.hs view
@@ -19,6 +19,8 @@      writeFileWithBackup,      writeFileWithBackupIfChanged,      readFileStrictly,+     pivotByOpts,+     anonymiseByOpts,      Test(TestList),     ) where@@ -27,7 +29,6 @@ import Data.Hashable (hash) import Data.List import Data.Maybe-import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.IO as T import Data.Time (Day)@@ -45,21 +46,8 @@ import Text.Printf import Text.Regex.TDFA ((=~)) ---- kludge - adapt to whichever directory version is installed, or when--- cabal macros aren't available, assume the new directory-#ifdef MIN_VERSION_directory-#if MIN_VERSION_directory(1,2,0)-#define directory_1_2-#endif-#else-#define directory_1_2-#endif--#ifdef directory_1_2 import System.Time (ClockTime(TOD)) import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds)-#endif  import Hledger.Cli.CliOptions import Hledger.Data@@ -75,9 +63,8 @@   -- We kludgily read the file before parsing to grab the full text, unless   -- it's stdin, or it doesn't exist and we are adding. We read it strictly   -- to let the add command work.-  rulespath <- rulesFilePathFromOpts opts   journalpaths <- journalFilePathFromOpts opts-  ej <- readJournalFiles Nothing rulespath (not $ ignore_assertions_ opts) journalpaths+  ej <- readJournalFilesWithOpts (inputopts_ opts) journalpaths   let f   = cmd opts           . pivotByOpts opts           . anonymiseByOpts opts@@ -89,19 +76,9 @@ pivotByOpts :: CliOpts -> Journal -> Journal pivotByOpts opts =   case maybestringopt "pivot" . rawopts_ $ opts of-    Just tag -> pivot $ T.pack tag+    Just tag -> journalPivot $ T.pack tag     Nothing  -> id --- | Apply the pivot transformation by given tag on a journal.-pivot :: Text -> Journal -> Journal-pivot tag j = j{jtxns = map pivotTrans . jtxns $ j}- where-  pivotTrans t = t{tpostings = map pivotPosting . tpostings $ t}-  pivotPosting p-    | Just (_ , value) <- tagTuple = p{paccount = value, porigin = Just $ originalPosting p}-    | _                <- tagTuple = p{paccount = T.pack "", porigin = Just $ originalPosting p}-   where tagTuple = find ((tag ==) . fst) . postingAllImplicitTags $ p- -- | Apply the anonymisation transformation on a journal, if option is present anonymiseByOpts :: CliOpts -> Journal -> Journal anonymiseByOpts opts =@@ -126,6 +103,10 @@   where     anon = T.pack . flip showHex "" . (fromIntegral :: Int -> Word32) . hash +-- XXX as of since 2017/4 this is used instead of +-- balanceReportValue/multiBalanceReportValue (mostly; not yet hledger-ui)+-- | If -V/--value was requested, convert all journal amounts to their market value+-- as of the report end date. Cf http://hledger.org/manual.html#market-value journalApplyValue :: ReportOpts -> Journal -> IO Journal journalApplyValue ropts j = do     mvaluedate <- reportEndDate j ropts@@ -137,6 +118,7 @@     return $ convert j  -- | Write some output to stdout or to a file selected by --output-file.+-- If the file exists it will be overwritten. writeOutput :: CliOpts -> String -> IO () writeOutput opts s = do   f <- outputFileFromOpts opts@@ -151,10 +133,9 @@ -- Reads the full journal, without filtering. journalReload :: CliOpts -> IO (Either String Journal) journalReload opts = do-  rulespath <- rulesFilePathFromOpts opts   journalpaths <- journalFilePathFromOpts opts   ((pivotByOpts opts . journalApplyAliases (aliasesFromOpts opts)) <$>) <$>-    readJournalFiles Nothing rulespath (not $ ignore_assertions_ opts) journalpaths+    readJournalFilesWithOpts (inputopts_ opts) journalpaths  -- | Re-read the option-specified journal file(s), but only if any of -- them has changed since last read. (If the file is standard input,@@ -195,13 +176,9 @@ fileModificationTime f     | null f = getClockTime     | otherwise = (do-#ifdef directory_1_2         utc <- getModificationTime f         let nom = utcTimeToPOSIXSeconds utc         let clo = TOD (read $ takeWhile (`elem` "0123456789") $ show nom) 0 -- XXX read-#else-        clo <- getModificationTime f-#endif         return clo         )         `C.catch` \(_::C.IOException) -> getClockTime
README.md view
@@ -115,7 +115,8 @@ --> <!-- [![gratipay](https://img.shields.io/gratipay/hledger.svg)]() --> -[![travis build status](https://img.shields.io/travis/simonmichael/hledger.svg)](https://travis-ci.org/simonmichael/hledger)+[![travis build status](https://img.shields.io/travis/simonmichael/hledger.svg)](https://travis.hledger.org)+[![appveyor windows build status](https://ci.appveyor.com/api/projects/status/5vejw0w5n5igdr42?svg=true)](https://appveyor.hledger.org) [![](https://img.shields.io/hackage-deps/v/hledger-lib.svg?label=hledger-lib+bounds)](http://packdeps.haskellers.com/feed?needle=hledger-lib) [![](https://img.shields.io/hackage-deps/v/hledger.svg?label=hledger+bounds)](http://packdeps.haskellers.com/feed?needle=hledger) [![](https://img.shields.io/hackage-deps/v/hledger-ui.svg?label=hledger-ui+bounds)](http://packdeps.haskellers.com/feed?needle=hledger-ui)
Text/Tabular/AsciiWide.hs view
@@ -70,7 +70,7 @@   coreLine = concatMap helper $ flattenHeader $ zipHeader 0 is h   helper = either hsep (uncurry padLeftWide)   hsep :: Properties -> String-  hsep NoLine     = " "+  hsep NoLine     = "  "   hsep SingleLine = midBar pretty   hsep DoubleLine = doubleMidBar pretty @@ -98,7 +98,7 @@   coreLine        = concatMap helper $ flattenHeader $ zipHeader 0 is h   helper          = either vsep dashes   dashes (i,_)    = replicate i sep-  vsep NoLine     = [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
doc/hledger.1 view
@@ -1,6 +1,6 @@ .\"t -.TH "hledger" "1" "August 2017" "hledger 1.3.1" "hledger User Manuals"+.TH "hledger" "1" "September 2017" "hledger 1.4" "hledger User Manuals"   @@ -156,31 +156,14 @@ .PP To see general usage help, including general options which are supported by most hledger commands, run \f[C]hledger\ \-h\f[].-(Note \-h and \-\-help are different, like git.) .PP General help options: .TP-.B \f[C]\-h\f[]+.B \f[C]\-h\ \-\-help\f[] show general usage (or after COMMAND, command usage) .RS .RE .TP-.B \f[C]\-\-help\f[]-show this program\[aq]s manual as plain text (or after an add\-on-COMMAND, the add\-on\[aq]s manual)-.RS-.RE-.TP-.B \f[C]\-\-man\f[]-show this program\[aq]s manual with man-.RS-.RE-.TP-.B \f[C]\-\-info\f[]-show this program\[aq]s manual with info-.RS-.RE-.TP .B \f[C]\-\-version\f[] show version .RS@@ -215,8 +198,8 @@ .RS .RE .TP-.B \f[C]\-\-pivot\ TAGNAME\f[]-use some other field/tag for account names+.B \f[C]\-\-pivot\ FIELDNAME\f[]+use some other field or tag for the account name .RS .RE .TP@@ -269,7 +252,7 @@ .RE .TP .B \f[C]\-\-date2\f[]-show, and match with \-b/\-e/\-p/date:, secondary dates instead+match the secondary date instead (see command help for other effects) .RS .RE .TP@@ -293,8 +276,8 @@ .RS .RE .TP-.B \f[C]\-\-depth=N\f[]-hide accounts/postings deeper than N+.B \f[C]\-NUM\ \-\-depth=NUM\f[]+hide/aggregate accounts or postings more than NUM levels deep .RS .RE .TP@@ -315,11 +298,10 @@ .RS .RE .PP-Note when multiple similar reporting options are provided, the last one-takes precedence.-Eg \f[C]\-p\ feb\ \-p\ mar\f[] is equivalent to \f[C]\-p\ mar\f[].+When a reporting option appears more than once in the command line, the+last one takes precedence. .PP-Some of these can also be written as queries.+Some reporting options can also be written as query arguments. .SS Command options .PP To see options for a particular command, including command\-specific@@ -337,6 +319,12 @@ .PP Most hledger commands accept arguments after the command name, which are often a query, filtering the data in some way.+.SS Argument expansion+.PP+You can save a set of command line options/arguments in a file, one per+line, and then reuse them by writing \f[C]\@FILE\f[] in a command line.+(To prevent this expansion of \f[C]\@\f[]\-arguments, precede them with+a \f[C]\-\-\f[] argument.) .SS Special characters .PP Option and argument values which contain problematic characters should@@ -353,13 +341,19 @@ \f[C]hledger\ balance\ cur:\[aq]\\$\[aq]\f[] or \f[C]hledger\ balance\ cur:\\\\$\f[]. .PP-There\[aq]s more..-options and arguments get de\-escaped when hledger is passing them to an-addon executable.-In this case you might need \f[I]triple\f[]\-escaping.+When hledger is invoking an addon executable (like hledger\-ui), options+and arguments get de\-escaped once more, so you might need+\f[I]triple\f[]\-escaping. Eg: \f[C]hledger\ ui\ cur:\[aq]\\\\$\[aq]\f[] or-\f[C]hledger\ ui\ cur:\\\\\\\\$\f[].+\f[C]hledger\ ui\ cur:\\\\\\\\$\f[] in bash.+(The number of backslashes in fish shell is left as an exercise for the+reader.) .PP+Inside a file used for argument expansion, one less level of escaping is+enough.+(And in this case, backslashes seem to work better than quotes.+Eg: \f[C]cur:\\$\f[]).+.PP If in doubt, keep things simple: .IP \[bu] 2 run add\-on executables directly@@ -758,29 +752,28 @@ \f[C]hledger\ register\ checking\ \-p\ "every\ 3rd\ day\ of\ week"\f[] .SS Depth limiting .PP-With the \f[C]\-\-depth\ N\f[] option, commands like account, balance-and register will show only the uppermost accounts in the account tree,-down to level N.+With the \f[C]\-\-depth\ N\f[] option (short form: \f[C]\-N\f[]),+commands like account, balance and register will show only the uppermost+accounts in the account tree, down to level N. Use this when you want a summary with less detail.+This flag has the same effect as a \f[C]depth:\f[] query argument (so+\f[C]\-2\f[], \f[C]\-\-depth=2\f[] or \f[C]depth:2\f[] are basically+equivalent). .SS Pivoting .PP Normally hledger sums amounts, and organizes them in a hierarchy, based on account name.-The \f[C]\-\-pivot\ TAGNAME\f[] option causes it to sum and organize-hierarchy based on some other field instead.-.PP-TAGNAME is the full, case\-insensitive name of a tag you have defined,-or one of the built\-in implicit tags (like \f[C]code\f[] or-\f[C]payee\f[]).-As with account names, when tag values have-\f[C]multiple:colon\-separated:parts\f[] hledger will build hierarchy,-displayed in tree\-mode reports, summarisable with a depth limit, and so-on.+The \f[C]\-\-pivot\ FIELD\f[] option causes it to sum and organize+hierarchy based on the value of some other field instead.+FIELD can be: \f[C]code\f[], \f[C]description\f[], \f[C]payee\f[],+\f[C]note\f[], or the full name (case insensitive) of any tag.+As with account names, values containing \f[C]colon:separated:parts\f[]+will be displayed hierarchically in reports. .PP \f[C]\-\-pivot\f[] is a general option affecting all reports; you can think of hledger transforming the journal before any other processing, replacing every posting\[aq]s account name with the value of the-specified tag on that posting, inheriting it from the transaction or+specified field on that posting, inheriting it from the transaction or using a blank value if it\[aq]s not present. .PP An example:@@ -957,12 +950,12 @@ after the command name, to filter the data by date, account name or other criteria. The syntax is similar to a web search: one or more space\-separated-search terms, quotes to enclose whitespace, optional prefixes to match-specific fields.-Multiple search terms are combined as follows:+search terms, quotes to enclose whitespace, prefixes to match specific+fields, a not: prefix to negate the match. .PP-All commands except print: show transactions/postings/accounts which-match (or negatively match)+We do not yet support arbitrary boolean combinations of search terms;+instead most commands show transactions/postings/accounts which match+(or negatively match): .IP \[bu] 2 any of the description terms AND .IP \[bu] 2@@ -972,7 +965,7 @@ .IP \[bu] 2 all the other terms. .PP-The print command: show transactions which+The print command instead shows transactions which: .IP \[bu] 2 match any of the description terms AND .IP \[bu] 2@@ -982,10 +975,13 @@ .IP \[bu] 2 match all the other terms. .PP-The following kinds of search terms can be used:+The following kinds of search terms can be used.+Remember these can also be prefixed with \f[B]\f[C]not:\f[]\f[], eg to+exclude a particular subaccount. .TP .B \f[B]\f[C]REGEX\f[]\f[]-match account names by this regular expression+match account names by this regular expression.+(No prefix is equivalent to \f[C]acct:\f[]). .RS .RE .TP@@ -1023,7 +1019,7 @@ .RE .TP .B \f[B]\f[C]desc:REGEX\f[]\f[]-match transaction descriptions+match transaction descriptions. .RS .RE .TP@@ -1047,6 +1043,18 @@ .RS .RE .TP+.B \f[B]\f[C]note:REGEX\f[]\f[]+match transaction notes (part of description right of \f[C]|\f[], or+whole description when there\[aq]s no \f[C]|\f[])+.RS+.RE+.TP+.B \f[B]\f[C]payee:REGEX\f[]\f[]+match transaction payee/payer names (part of description left of+\f[C]|\f[], or whole description when there\[aq]s no \f[C]|\f[])+.RS+.RE+.TP .B \f[B]\f[C]real:,\ real:0\f[]\f[] match real or virtual postings respectively .RS@@ -1065,18 +1073,13 @@ transaction. .RS .RE-.TP-.B \f[B]\f[C]not:\f[]\f[]-before any of the above negates the match.-.RS-.RE+.PP+The following special search term is used automatically in hledger\-web,+only: .TP .B \f[B]\f[C]inacct:ACCTNAME\f[]\f[]-a special term used automatically when you click an account name in-hledger\-web, specifying the account register we are currently in-(selects the transactions of that account and how to show them, can be-filtered further with \f[C]acct\f[] etc).-Not supported elsewhere in hledger.+tells hledger\-web to show the transaction register for this account.+Can be filtered further with \f[C]acct\f[] etc. .RS .RE .PP@@ -1096,12 +1099,17 @@ .PP Run a subcommand by writing its name as first argument (eg \f[C]hledger\ incomestatement\f[]).-You can also write any unambiguous prefix of a command name-(\f[C]hledger\ inc\f[]), or one of the standard short aliases displayed-in the command list (\f[C]hledger\ is\f[]).+You can also write one of the standard short aliases displayed in+parentheses in the command list (\f[C]hledger\ b\f[]), or any any+unambiguous prefix of a command name (\f[C]hledger\ inc\f[]).+.PP+Here are all the builtin commands in alphabetical order.+See also \f[C]hledger\f[] for a more organised command list, and+\f[C]hledger\ CMD\ \-h\f[] for detailed command help. .SS accounts .PP Show account names.+Alias: a. .TP .B \f[C]\-\-tree\f[] show short account names, as a tree@@ -1278,7 +1286,7 @@ .SS balance .PP Show accounts and their balances.-Alias: bal.+Aliases: b, bal. .TP .B \f[C]\-\-change\f[] show balance change in each period (default)@@ -1354,6 +1362,12 @@ Use unicode to display prettier tables. .RS .RE+.TP+.B \f[C]\-\-sort\-amount\f[]+Sort by amount (total row amount, or by average if that is displayed),+instead of account name (in flat mode)+.RS+.RE .PP The balance command displays accounts and balances. It is hledger\[aq]s most featureful and versatile command.@@ -1732,6 +1746,11 @@ in single\-column balance reports: use this custom line format .RS .RE+.TP+.B \f[C]\-\-sort\-amount\f[]+sort by amount instead of account name+.RS+.RE .PP This command displays a simple balance sheet. It currently assumes that you have top\-level accounts named@@ -1767,6 +1786,47 @@ Normally balancesheet shows historical ending balances, which is what you need for a balance sheet; note this means it ignores report begin dates.+.SS balancesheetequity+.PP+Show a balance sheet including equity.+Alias: bse.+.PP+Other than showing the equity accounts, this command is exactly the same+as the command balancesheet.+Please refer to it for the available options.+.PP+This command displays a balancesheet.+It currently assumes that you have top\-level accounts named+\f[C]asset\f[], \f[C]liability\f[] and \f[C]equity\f[] (plural forms+also allowed.)+.IP+.nf+\f[C]+$\ hledger\ balancesheetequity+Balance\ Sheet\ With\ Equity++Assets:+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $\-2\ \ assets+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $1\ \ \ \ bank:saving+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $\-3\ \ \ \ cash+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $\-2++Liabilities:+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $1\ \ liabilities:debts+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $1++Equity:+\ \ \ \ \ \ \ \ \ \ $1\ \ equity:owner+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\ \ \ \ \ \ \ \ \ \ $1++Total:+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 0+\f[]+.fi .SS cashflow .PP Show a cashflow statement.@@ -1830,12 +1890,17 @@ in single\-column balance reports: use this custom line format .RS .RE+.TP+.B \f[C]\-\-sort\-amount\f[]+sort by amount instead of account name+.RS+.RE .PP This command displays a simple cashflow statement It shows the change in all "cash" (ie, liquid assets) accounts for the period. It currently assumes that cash accounts are under a top\-level account-named \f[C]asset\f[] and do not contain \f[C]receivable\f[] or-\f[C]A/R\f[] (plural forms also allowed.)+named \f[C]asset\f[] and do not contain \f[C]receivable\f[],+\f[C]:A/R\f[] or \f[C]:fixed\f[]. .IP .nf \f[C]@@ -1860,44 +1925,77 @@ Normally cashflow shows changes in assets per period, though as with multicolumn balance reports you can alter the report mode with \f[C]\-\-change\f[]/\f[C]\-\-cumulative\f[]/\f[C]\-\-historical\f[].+.SS check\-dates+.PP+Check that transactions are sorted by increasing date.+With a query, only matched transactions\[aq] dates are checked.+.SS check\-dupes+.PP+Report account names having the same leaf but different prefixes.+An example: http://stefanorodighiero.net/software/hledger\-dupes.html+.SS equity+.PP+Print closing/opening transactions that bring some or all account+balances to zero and back.+Can be useful for bringing account balances across file boundaries. .SS help .PP Show any of the hledger manuals. .PP-The \f[C]help\f[] command displays any of the main hledger man pages.-(Unlike \f[C]hledger\ \-\-help\f[], which displays only the hledger man-page.) Run it with no arguments to list available topics (their names-are shortened for easier typing), and run \f[C]hledger\ help\ TOPIC\f[]-to select one.-The output is similar to a man page, but fixed width.-It may be long, so you may wish to pipe it into a pager.-See also info and man.+The \f[C]help\f[] command displays any of the main hledger manuals, in+one of several ways.+Run it with no argument to list the manuals, or provide a full or+partial manual name to select one.+.PP+hledger manuals are available in several formats.+hledger help will use the first of these display methods that it finds:+info, man, $PAGER, less, stdout (or when non\-interactive, just stdout).+You can force a particular viewer with the \f[C]\-\-info\f[],+\f[C]\-\-man\f[], \f[C]\-\-pager\f[], \f[C]\-\-cat\f[] flags. .IP .nf \f[C] $\ hledger\ help-Choose\ a\ topic,\ eg:\ hledger\ help\ cli-cli,\ ui,\ web,\ api,\ journal,\ csv,\ timeclock,\ timedot+Please\ choose\ a\ manual\ by\ typing\ "hledger\ help\ MANUAL"\ (a\ substring\ is\ ok).+Manuals:\ hledger\ hledger\-ui\ hledger\-web\ hledger\-api\ journal\ csv\ timeclock\ timedot \f[] .fi .IP .nf \f[C]-$\ hledger\ help\ cli\ |\ less--hledger(1)\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ hledger\ User\ Manuals\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ hledger(1)-+$\ hledger\ help\ h\ \-\-man +hledger(1)\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ hledger\ User\ Manuals\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ hledger(1)  NAME \ \ \ \ \ \ \ hledger\ \-\ a\ command\-line\ accounting\ tool  SYNOPSIS-\ \ \ \ \ \ \ hledger\ [\-f\ FILE]\ COMMAND\ [OPTIONS]\ [CMDARGS]-\ \ \ \ \ \ \ hledger\ [\-f\ FILE]\ ADDONCMD\ \-\-\ [OPTIONS]\ [CMDARGS]-:+\ \ \ \ \ \ \ hledger\ [\-f\ FILE]\ COMMAND\ [OPTIONS]\ [ARGS]+\ \ \ \ \ \ \ hledger\ [\-f\ FILE]\ ADDONCMD\ \-\-\ [OPTIONS]\ [ARGS]+\ \ \ \ \ \ \ hledger++DESCRIPTION+\ \ \ \ \ \ \ hledger\ \ is\ \ a\ \ cross\-platform\ \ program\ \ for\ tracking\ money,\ time,\ or\ any+\&... \f[] .fi+.SS import+.PP+Read new transactions added to each FILE since last run, and add them to+the main journal file.+.TP+.B \f[C]\-\-dry\-run\f[]+just show the transactions to be imported+.RS+.RE+.PP+Input files are provided as arguments, or glob patterns.+So eg to add new transactions from all CSV files to the main journal:+hledger import *.csv+.PP+New transactions are detected like print \-\-new (using .latest.FILE+state files). .SS incomestatement .PP Show an income statement.@@ -1961,6 +2059,11 @@ in single\-column balance reports: use this custom line format .RS .RE+.TP+.B \f[C]\-\-sort\-amount\f[]+sort by amount instead of account name+.RS+.RE .PP This command displays a simple income statement. It currently assumes that you have top\-level accounts named@@ -1997,37 +2100,13 @@ Normally incomestatement shows revenues/expenses per period, though as with multicolumn balance reports you can alter the report mode with \f[C]\-\-change\f[]/\f[C]\-\-cumulative\f[]/\f[C]\-\-historical\f[].-.SS info-.PP-Show any of the hledger manuals using info.-.PP-The \f[C]info\f[] command displays any of the hledger reference manuals-using the info hypertextual documentation viewer.-This can be a very efficient way to browse large manuals.-It requires the "info" program to be available in your PATH.-.PP-As with help, run it with no arguments to list available topics-(manuals).-.SS man-.PP-Show any of the hledger manuals using man.-.PP-The \f[C]man\f[] command displays any of the hledger reference manuals-using man, the standard documentation viewer on unix systems.-This will fit the text to your terminal width, and probably invoke a-pager automatically.-It requires the "man" program to be available in your PATH.+.SS prices .PP-As with help, run it with no arguments to list available topics-(manuals).+Print all market prices from the journal. .SS print .PP Show transactions from the journal.-.TP-.B \f[C]\-x\ \ \ \ \ \-\-explicit\f[]-show all amounts explicitly-.RS-.RE+Aliases: p, txns. .TP .B \f[C]\-m\ STR\ \-\-match=STR\f[] show the transaction whose description is most similar to STR, and is@@ -2035,6 +2114,16 @@ .RS .RE .TP+.B \f[C]\-\-new\f[]+show only newer\-dated transactions added in each file since last run+.RS+.RE+.TP+.B \f[C]\-x\ \ \ \ \ \-\-explicit\f[]+show all amounts explicitly+.RS+.RE+.TP .B \f[C]\-O\ FMT\ \-\-output\-format=FMT\f[] select the output format. Supported formats: txt, csv.@@ -2074,25 +2163,54 @@ .fi .PP The print command displays full journal entries (transactions) from the-journal file, tidily formatted.-.PP-As of hledger 1.2, print\[aq]s output is always a valid hledger journal.-However it may not preserve all original content, eg it does not print-directives or inter\-transaction comments.+journal file in date order, tidily formatted.+print\[aq]s output is always a valid hledger journal.+It preserves all transaction information, but it does not preserve+directives or inter\-transaction comments .PP-Normally, transactions\[aq] implicit/explicit amount style is preserved:-when an amount is omitted in the journal, it will be omitted in the+Normally, the journal entry\[aq]s explicit or implicit amount style is+preserved.+Ie when an amount is omitted in the journal, it will be omitted in the output.-You can use the \f[C]\-x/\-\-explicit\f[] flag to make all amounts-explicit, which can be useful for troubleshooting or for making your-journal more readable and robust against data entry errors.-Note, in this mode postings with a multi\-commodity amount (possible-with an implicit amount in a multi\-commodity transaction) will be split-into multiple single\-commodity postings, for valid journal output.+You can use the \f[C]\-x\f[]/\f[C]\-\-explicit\f[] flag to make all+amounts explicit, which can be useful for troubleshooting or for making+your journal more readable and robust against data entry errors.+Note, \f[C]\-x\f[] will cause postings with a multi\-commodity amount+(these can arise when a multi\-commodity transaction has an implicit+amount) will be split into multiple single\-commodity postings, for+valid journal output. .PP-With \-B/\-\-cost, amounts with transaction prices are converted to cost-(using the transaction price).+With \f[C]\-B\f[]/\f[C]\-\-cost\f[], amounts with transaction prices are+converted to cost using that price. .PP+With \f[C]\-m\f[]/\f[C]\-\-match\f[] and a STR argument, print will show+at most one transaction: the one one whose description is most similar+to STR, and is most recent.+STR should contain at least two characters.+If there is no similar\-enough match, no transaction will be shown.+.PP+With \f[C]\-\-new\f[], for each FILE being read, hledger reads (and+writes) a special state file (\f[C]\&.latest.FILE\f[] in the same+directory), containing the latest transaction date(s) that were seen+last time FILE was read.+When this file is found, only transactions with newer dates (and new+transactions on the latest date) are printed.+This is useful for ignoring already\-seen entries in import data, such+as downloaded CSV files.+Eg:+.IP+.nf+\f[C]+$\ hledger\ \-f\ bank1.csv\ print\ \-\-new+#\ shows\ transactions\ added\ since\ last\ print\ \-\-new\ on\ this\ file+\f[]+.fi+.PP+This assumes that transactions added to FILE always have same or+increasing dates, and that transactions on the same day do not get+reordered.+See also the import command.+.PP The print command also supports output destination and CSV output. Here\[aq]s an example of print\[aq]s CSV output: .IP@@ -2129,10 +2247,13 @@ for convenience. (Those names are not accurate in the accounting sense; it just puts negative amounts under credit and zero or greater amounts under debit.)+.SS print\-unique+.PP+Print transactions which do not reuse an already\-seen description. .SS register .PP Show postings and their running total.-Alias: reg.+Aliases: r, reg. .TP .B \f[C]\-\-cumulative\f[] show running total from report start date (default)@@ -2305,6 +2426,14 @@ The register command also supports the \f[C]\-o/\-\-output\-file\f[] and \f[C]\-O/\-\-output\-format\f[] options for controlling output destination and CSV output.+.SS register\-match+.PP+Print the one posting whose transaction description is closest to DESC,+in the style of the register command.+Helps ledger\-autosync detect already\-seen transactions when importing.+.SS rewrite+.PP+Print all transactions, adding custom postings to the matched ones. .SS stats .PP Show some journal statistics.@@ -2337,6 +2466,9 @@ .PP The stats command also supports \f[C]\-o/\-\-output\-file\f[] for controlling output destination.+.SS tags+.PP+List all the tag names in use. .SS test .PP Run built\-in unit tests.@@ -2440,33 +2572,6 @@ .SS check .PP hledger\-check.hs checks more powerful account balance assertions.-.SS check\-dates-.PP-hledger\-check\-dates.hs checks that journal entries are ordered by-date.-.SS check\-dupes-.PP-hledger\-check\-dupes.hs checks for account names sharing the same leaf-name.-.SS equity-.PP-hledger\-equity.hs prints balance\-resetting transactions, useful for-bringing account balances across file boundaries.-.SS prices-.PP-hledger\-prices.hs prints all prices from the journal.-.SS print\-unique-.PP-hledger\-print\-unique.hs prints transactions which do not reuse an-already\-seen description.-.SS register\-match-.PP-hledger\-register\-match.hs helps ledger\-autosync detect already\-seen-transactions when importing.-.SS rewrite-.PP-hledger\-rewrite.hs Adds one or more custom postings to matched-transactions. .SH ENVIRONMENT .PP \f[B]COLUMNS\f[] The screen width used by the register command.
doc/hledger.1.info view
@@ -3,8 +3,8 @@  File: hledger.1.info,  Node: Top,  Next: EXAMPLES,  Up: (dir) -hledger(1) hledger 1.3.1-************************+hledger(1) hledger 1.4+**********************  This is hledger's command-line interface (there are also curses and web interfaces).  Its basic function is to read a plain text file describing@@ -118,6 +118,7 @@ * General options:: * Command options:: * Command arguments::+* Argument expansion:: * Special characters:: * Input files:: * Smart dates::@@ -137,24 +138,13 @@ ===================  To see general usage help, including general options which are supported-by most hledger commands, run 'hledger -h'.  (Note -h and -help are-different, like git.)+by most hledger commands, run 'hledger -h'.     General help options: -'-h'+'-h --help'       show general usage (or after COMMAND, command usage)-'--help'--     show this program's manual as plain text (or after an add-on-     COMMAND, the add-on's manual)-'--man'--     show this program's manual with man-'--info'--     show this program's manual with info '--version'       show version@@ -177,9 +167,9 @@ '--anon'       anonymize accounts and payees-'--pivot TAGNAME'+'--pivot FIELDNAME' -     use some other field/tag for account names+     use some other field or tag for the account name '-I --ignore-assertions'       ignore any failing balance assertions@@ -213,7 +203,8 @@      (overrides the flags above) '--date2' -     show, and match with -b/-e/-p/date:, secondary dates instead+     match the secondary date instead (see command help for other+     effects) '-U --unmarked'       include only unmarked postings/txns (can combine with -P or -C)@@ -226,9 +217,9 @@ '-R --real'       include only non-virtual postings-'--depth=N'+'-NUM --depth=NUM' -     hide accounts/postings deeper than N+     hide/aggregate accounts or postings more than NUM levels deep '-E --empty'       show items with zero amount, normally hidden@@ -241,10 +232,10 @@      convert amounts to their market value on the report end date (using      the most recent applicable market price, if any) -   Note when multiple similar reporting options are provided, the last-one takes precedence.  Eg '-p feb -p mar' is equivalent to '-p mar'.+   When a reporting option appears more than once in the command line,+the last one takes precedence. -   Some of these can also be written as queries.+   Some reporting options can also be written as query arguments.   File: hledger.1.info,  Node: Command options,  Next: Command arguments,  Prev: General options,  Up: OPTIONS@@ -263,7 +254,7 @@ run the addon executable directly: 'hledger-ui --watch'.  -File: hledger.1.info,  Node: Command arguments,  Next: Special characters,  Prev: Command options,  Up: OPTIONS+File: hledger.1.info,  Node: Command arguments,  Next: Argument expansion,  Prev: Command options,  Up: OPTIONS  2.3 Command arguments =====================@@ -272,11 +263,22 @@ often a query, filtering the data in some way.  -File: hledger.1.info,  Node: Special characters,  Next: Input files,  Prev: Command arguments,  Up: OPTIONS+File: hledger.1.info,  Node: Argument expansion,  Next: Special characters,  Prev: Command arguments,  Up: OPTIONS -2.4 Special characters+2.4 Argument expansion ====================== +You can save a set of command line options/arguments in a file, one per+line, and then reuse them by writing '@FILE' in a command line.  (To+prevent this expansion of '@'-arguments, precede them with a '--'+argument.)+++File: hledger.1.info,  Node: Special characters,  Next: Input files,  Prev: Argument expansion,  Up: OPTIONS++2.5 Special characters+======================+ Option and argument values which contain problematic characters should be escaped with double quotes, backslashes, or (best) single quotes. Problematic characters means spaces, and also characters which are@@ -290,11 +292,16 @@ dollar symbol, bash users should do: 'hledger balance cur:'\$'' or 'hledger balance cur:\\$'. -   There's more..  options and arguments get de-escaped when hledger is-passing them to an addon executable.  In this case you might need-_triple_-escaping.  Eg: 'hledger ui cur:'\\$'' or 'hledger ui-cur:\\\\$'.+   When hledger is invoking an addon executable (like hledger-ui),+options and arguments get de-escaped once more, so you might need+_triple_-escaping.  Eg: 'hledger ui cur:'\\$'' or 'hledger ui cur:\\\\$'+in bash.  (The number of backslashes in fish shell is left as an+exercise for the reader.) +   Inside a file used for argument expansion, one less level of escaping+is enough.  (And in this case, backslashes seem to work better than+quotes.  Eg: 'cur:\$').+    If in doubt, keep things simple:     * run add-on executables directly@@ -307,7 +314,7 @@  File: hledger.1.info,  Node: Input files,  Next: Smart dates,  Prev: Special characters,  Up: OPTIONS -2.5 Input files+2.6 Input files ===============  hledger reads transactions from a data file (and the add command writes@@ -362,7 +369,7 @@  File: hledger.1.info,  Node: Smart dates,  Next: Report start & end date,  Prev: Input files,  Up: OPTIONS -2.6 Smart dates+2.7 Smart dates ===============  hledger's user interfaces accept a flexible "smart date" syntax (unlike@@ -385,7 +392,7 @@  File: hledger.1.info,  Node: Report start & end date,  Next: Report intervals,  Prev: Smart dates,  Up: OPTIONS -2.7 Report start & end date+2.8 Report start & end date ===========================  Most hledger reports show the full span of time represented by the@@ -414,7 +421,7 @@  File: hledger.1.info,  Node: Report intervals,  Next: Period expressions,  Prev: Report start & end date,  Up: OPTIONS -2.8 Report intervals+2.9 Report intervals ====================  A report interval can be specified so that commands like register,@@ -427,8 +434,8 @@  File: hledger.1.info,  Node: Period expressions,  Next: Depth limiting,  Prev: Report intervals,  Up: OPTIONS -2.9 Period expressions-======================+2.10 Period expressions+=======================  The '-p/--period' option accepts period expressions, a shorthand way of expressing a start date, end date, and/or report interval all at once.@@ -502,34 +509,33 @@  File: hledger.1.info,  Node: Depth limiting,  Next: Pivoting,  Prev: Period expressions,  Up: OPTIONS -2.10 Depth limiting+2.11 Depth limiting =================== -With the '--depth N' option, commands like account, balance and register-will show only the uppermost accounts in the account tree, down to level-N. Use this when you want a summary with less detail.+With the '--depth N' option (short form: '-N'), commands like account,+balance and register will show only the uppermost accounts in the+account tree, down to level N. Use this when you want a summary with+less detail.  This flag has the same effect as a 'depth:' query argument+(so '-2', '--depth=2' or 'depth:2' are basically equivalent).   File: hledger.1.info,  Node: Pivoting,  Next: Cost,  Prev: Depth limiting,  Up: OPTIONS -2.11 Pivoting+2.12 Pivoting =============  Normally hledger sums amounts, and organizes them in a hierarchy, based-on account name.  The '--pivot TAGNAME' option causes it to sum and-organize hierarchy based on some other field instead.--   TAGNAME is the full, case-insensitive name of a tag you have defined,-or one of the built-in implicit tags (like 'code' or 'payee').  As with-account names, when tag values have 'multiple:colon-separated:parts'-hledger will build hierarchy, displayed in tree-mode reports,-summarisable with a depth limit, and so on.+on account name.  The '--pivot FIELD' option causes it to sum and+organize hierarchy based on the value of some other field instead.+FIELD can be: 'code', 'description', 'payee', 'note', or the full name+(case insensitive) of any tag.  As with account names, values containing+'colon:separated:parts' will be displayed hierarchically in reports.     '--pivot' is a general option affecting all reports; you can think of hledger transforming the journal before any other processing, replacing-every posting's account name with the value of the specified tag on that-posting, inheriting it from the transaction or using a blank value if-it's not present.+every posting's account name with the value of the specified field on+that posting, inheriting it from the transaction or using a blank value+if it's not present.     An example: @@ -572,7 +578,7 @@  File: hledger.1.info,  Node: Cost,  Next: Market value,  Prev: Pivoting,  Up: OPTIONS -2.12 Cost+2.13 Cost =========  The '-B/--cost' flag converts amounts to their cost at transaction time,@@ -581,7 +587,7 @@  File: hledger.1.info,  Node: Market value,  Next: Regular expressions,  Prev: Cost,  Up: OPTIONS -2.13 Market value+2.14 Market value =================  The '-V/--value' flag converts the reported amounts to their market@@ -630,7 +636,7 @@  File: hledger.1.info,  Node: Regular expressions,  Prev: Market value,  Up: OPTIONS -2.14 Regular expressions+2.15 Regular expressions ========================  hledger uses regular expressions in a number of places:@@ -678,29 +684,32 @@ expression, written as arguments after the command name, to filter the data by date, account name or other criteria.  The syntax is similar to a web search: one or more space-separated search terms, quotes to-enclose whitespace, optional prefixes to match specific fields.-Multiple search terms are combined as follows:+enclose whitespace, prefixes to match specific fields, a not: prefix to+negate the match. -   All commands except print: show transactions/postings/accounts which-match (or negatively match)+   We do not yet support arbitrary boolean combinations of search terms;+instead most commands show transactions/postings/accounts which match+(or negatively match):     * any of the description terms AND    * any of the account terms AND    * any of the status terms AND    * all the other terms. -   The print command: show transactions which+   The print command instead shows transactions which:     * match any of the description terms AND    * have any postings matching any of the positive account terms AND    * have no postings matching any of the negative account terms AND    * match all the other terms. -   The following kinds of search terms can be used:+   The following kinds of search terms can be used.  Remember these can+also be prefixed with *'not:'*, eg to exclude a particular subaccount.  *'REGEX'* -     match account names by this regular expression+     match account names by this regular expression.  (No prefix is+     equivalent to 'acct:'). *'acct:REGEX'*       same as above@@ -726,7 +735,7 @@      print cur:'\$'' or 'hledger print cur:\\$'. *'desc:REGEX'* -     match transaction descriptions+     match transaction descriptions. *'date:PERIODEXPR'*       match dates within the specified period.  PERIODEXPR is a period@@ -741,6 +750,14 @@       match (or display, depending on command) accounts at or above this      depth+*'note:REGEX'*++     match transaction notes (part of description right of '|', or whole+     description when there's no '|')+*'payee:REGEX'*++     match transaction payee/payer names (part of description left of+     '|', or whole description when there's no '|') *'real:, real:0'*       match real or virtual postings respectively@@ -753,16 +770,14 @@      query is considered to match a transaction if it matches any of the      postings.  Also remember that postings inherit the tags of their      parent transaction.-*'not:'* -     before any of the above negates the match.+   The following special search term is used automatically in+hledger-web, only:+ *'inacct:ACCTNAME'* -     a special term used automatically when you click an account name in-     hledger-web, specifying the account register we are currently in-     (selects the transactions of that account and how to show them, can-     be filtered further with 'acct' etc).  Not supported elsewhere in-     hledger.+     tells hledger-web to show the transaction register for this+     account.  Can be filtered further with 'acct' etc.     Some of these can also be expressed as command-line options (eg 'depth:2' is equivalent to '--depth 2').  Generally you can mix options@@ -783,9 +798,13 @@ be listed as subcommands.     Run a subcommand by writing its name as first argument (eg 'hledger-incomestatement').  You can also write any unambiguous prefix of a-command name ('hledger inc'), or one of the standard short aliases-displayed in the command list ('hledger is').+incomestatement').  You can also write one of the standard short aliases+displayed in parentheses in the command list ('hledger b'), or any any+unambiguous prefix of a command name ('hledger inc').++   Here are all the builtin commands in alphabetical order.  See also+'hledger' for a more organised command list, and 'hledger CMD -h' for+detailed command help. * Menu:  * accounts::@@ -793,14 +812,22 @@ * add:: * balance:: * balancesheet::+* balancesheetequity:: * cashflow::+* check-dates::+* check-dupes::+* equity:: * help::+* import:: * incomestatement::-* info::-* man::+* prices:: * print::+* print-unique:: * register::+* register-match::+* rewrite:: * stats::+* tags:: * test::  @@ -809,7 +836,7 @@ 4.1 accounts ============ -Show account names.+Show account names.  Alias: a.  '--tree' @@ -962,7 +989,7 @@ 4.4 balance =========== -Show accounts and their balances.  Alias: bal.+Show accounts and their balances.  Aliases: b, bal.  '--change' @@ -1011,7 +1038,11 @@ '--pretty-tables'       Use unicode to display prettier tables.+'--sort-amount' +     Sort by amount (total row amount, or by average if that is+     displayed), instead of account name (in flat mode)+    The balance command displays accounts and balances.  It is hledger's most featureful and versatile command. @@ -1298,7 +1329,7 @@ $ hledger balance -o FILE.csv  # write CSV to FILE.csv  -File: hledger.1.info,  Node: balancesheet,  Next: cashflow,  Prev: balance,  Up: COMMANDS+File: hledger.1.info,  Node: balancesheet,  Next: balancesheetequity,  Prev: balance,  Up: COMMANDS  4.5 balancesheet ================@@ -1343,7 +1374,10 @@ '--format=LINEFORMAT'       in single-column balance reports: use this custom line format+'--sort-amount' +     sort by amount instead of account name+    This command displays a simple balance sheet.  It currently assumes that you have top-level accounts named 'asset' and 'liability' (plural forms also allowed.)@@ -1374,9 +1408,49 @@ for a balance sheet; note this means it ignores report begin dates.  -File: hledger.1.info,  Node: cashflow,  Next: help,  Prev: balancesheet,  Up: COMMANDS+File: hledger.1.info,  Node: balancesheetequity,  Next: cashflow,  Prev: balancesheet,  Up: COMMANDS -4.6 cashflow+4.6 balancesheetequity+======================++Show a balance sheet including equity.  Alias: bse.++   Other than showing the equity accounts, this command is exactly the+same as the command balancesheet.  Please refer to it for the available+options.++   This command displays a balancesheet.  It currently assumes that you+have top-level accounts named 'asset', 'liability' and 'equity' (plural+forms also allowed.)++$ hledger balancesheetequity+Balance Sheet With Equity++Assets:+                 $-2  assets+                  $1    bank:saving+                 $-3    cash+--------------------+                 $-2++Liabilities:+                  $1  liabilities:debts+--------------------+                  $1++Equity:+          $1  equity:owner+--------------------+          $1++Total:+--------------------+                   0+++File: hledger.1.info,  Node: cashflow,  Next: check-dates,  Prev: balancesheetequity,  Up: COMMANDS++4.7 cashflow ============  Show a cashflow statement.  Alias: cf.@@ -1418,11 +1492,14 @@ '--format=LINEFORMAT'       in single-column balance reports: use this custom line format+'--sort-amount' +     sort by amount instead of account name+    This command displays a simple cashflow statement It shows the change in all "cash" (ie, liquid assets) accounts for the period.  It currently assumes that cash accounts are under a top-level account named 'asset'-and do not contain 'receivable' or 'A/R' (plural forms also allowed.)+and do not contain 'receivable', ':A/R' or ':fixed'.  $ hledger cashflow Cashflow Statement@@ -1444,44 +1521,96 @@ report mode with '--change'/'--cumulative'/'--historical'.  -File: hledger.1.info,  Node: help,  Next: incomestatement,  Prev: cashflow,  Up: COMMANDS+File: hledger.1.info,  Node: check-dates,  Next: check-dupes,  Prev: cashflow,  Up: COMMANDS -4.7 help-========+4.8 check-dates+=============== -Show any of the hledger manuals.+Check that transactions are sorted by increasing date.  With a query,+only matched transactions' dates are checked. -   The 'help' command displays any of the main hledger man pages.-(Unlike 'hledger --help', which displays only the hledger man page.)-Run it with no arguments to list available topics (their names are-shortened for easier typing), and run 'hledger help TOPIC' to select-one.  The output is similar to a man page, but fixed width.  It may be-long, so you may wish to pipe it into a pager.  See also info and man.++File: hledger.1.info,  Node: check-dupes,  Next: equity,  Prev: check-dates,  Up: COMMANDS -$ hledger help-Choose a topic, eg: hledger help cli-cli, ui, web, api, journal, csv, timeclock, timedot+4.9 check-dupes+=============== -$ hledger help cli | less+Report account names having the same leaf but different prefixes.  An+example: http://stefanorodighiero.net/software/hledger-dupes.html -hledger(1)                   hledger User Manuals                   hledger(1)++File: hledger.1.info,  Node: equity,  Next: help,  Prev: check-dupes,  Up: COMMANDS +4.10 equity+=========== +Print closing/opening transactions that bring some or all account+balances to zero and back.  Can be useful for bringing account balances+across file boundaries. ++File: hledger.1.info,  Node: help,  Next: import,  Prev: equity,  Up: COMMANDS++4.11 help+=========++Show any of the hledger manuals.++   The 'help' command displays any of the main hledger manuals, in one+of several ways.  Run it with no argument to list the manuals, or+provide a full or partial manual name to select one.++   hledger manuals are available in several formats.  hledger help will+use the first of these display methods that it finds: info, man, $PAGER,+less, stdout (or when non-interactive, just stdout).  You can force a+particular viewer with the '--info', '--man', '--pager', '--cat' flags.++$ hledger help+Please choose a manual by typing "hledger help MANUAL" (a substring is ok).+Manuals: hledger hledger-ui hledger-web hledger-api journal csv timeclock timedot++$ hledger help h --man++hledger(1)                    hledger User Manuals                    hledger(1)+ NAME        hledger - a command-line accounting tool  SYNOPSIS-       hledger [-f FILE] COMMAND [OPTIONS] [CMDARGS]-       hledger [-f FILE] ADDONCMD -- [OPTIONS] [CMDARGS]-:+       hledger [-f FILE] COMMAND [OPTIONS] [ARGS]+       hledger [-f FILE] ADDONCMD -- [OPTIONS] [ARGS]+       hledger +DESCRIPTION+       hledger  is  a  cross-platform  program  for tracking money, time, or any+...+ -File: hledger.1.info,  Node: incomestatement,  Next: info,  Prev: help,  Up: COMMANDS+File: hledger.1.info,  Node: import,  Next: incomestatement,  Prev: help,  Up: COMMANDS -4.8 incomestatement-===================+4.12 import+=========== +Read new transactions added to each FILE since last run, and add them to+the main journal file.++'--dry-run'++     just show the transactions to be imported++   Input files are provided as arguments, or glob patterns.  So eg to+add new transactions from all CSV files to the main journal: hledger+import *.csv++   New transactions are detected like print -new (using .latest.FILE+state files).+++File: hledger.1.info,  Node: incomestatement,  Next: prices,  Prev: import,  Up: COMMANDS++4.13 incomestatement+====================+ Show an income statement.  Alias: is.  '--change'@@ -1521,7 +1650,10 @@ '--format=LINEFORMAT'       in single-column balance reports: use this custom line format+'--sort-amount' +     sort by amount instead of account name+    This command displays a simple income statement.  It currently assumes that you have top-level accounts named 'income' (or 'revenue') and 'expense' (plural forms also allowed.)@@ -1553,53 +1685,32 @@ report mode with '--change'/'--cumulative'/'--historical'.  -File: hledger.1.info,  Node: info,  Next: man,  Prev: incomestatement,  Up: COMMANDS--4.9 info-========--Show any of the hledger manuals using info.--   The 'info' command displays any of the hledger reference manuals-using the info hypertextual documentation viewer.  This can be a very-efficient way to browse large manuals.  It requires the "info" program-to be available in your PATH.--   As with help, run it with no arguments to list available topics-(manuals).---File: hledger.1.info,  Node: man,  Next: print,  Prev: info,  Up: COMMANDS--4.10 man-========--Show any of the hledger manuals using man.+File: hledger.1.info,  Node: prices,  Next: print,  Prev: incomestatement,  Up: COMMANDS -   The 'man' command displays any of the hledger reference manuals using-man, the standard documentation viewer on unix systems.  This will fit-the text to your terminal width, and probably invoke a pager-automatically.  It requires the "man" program to be available in your-PATH.+4.14 prices+=========== -   As with help, run it with no arguments to list available topics-(manuals).+Print all market prices from the journal.  -File: hledger.1.info,  Node: print,  Next: register,  Prev: man,  Up: COMMANDS+File: hledger.1.info,  Node: print,  Next: print-unique,  Prev: prices,  Up: COMMANDS -4.11 print+4.15 print ========== -Show transactions from the journal.--'-x --explicit'+Show transactions from the journal.  Aliases: p, txns. -     show all amounts explicitly '-m STR --match=STR'       show the transaction whose description is most similar to STR, and      is most recent+'--new'++     show only newer-dated transactions added in each file since last+     run+'-x --explicit'++     show all amounts explicitly '-O FMT --output-format=FMT'       select the output format.  Supported formats: txt, csv.@@ -1631,24 +1742,43 @@     assets:bank:checking           $-1     The print command displays full journal entries (transactions) from-the journal file, tidily formatted.+the journal file in date order, tidily formatted.  print's output is+always a valid hledger journal.  It preserves all transaction+information, but it does not preserve directives or inter-transaction+comments -   As of hledger 1.2, print's output is always a valid hledger journal.-However it may not preserve all original content, eg it does not print-directives or inter-transaction comments.+   Normally, the journal entry's explicit or implicit amount style is+preserved.  Ie when an amount is omitted in the journal, it will be+omitted in the output.  You can use the '-x'/'--explicit' flag to make+all amounts explicit, which can be useful for troubleshooting or for+making your journal more readable and robust against data entry errors.+Note, '-x' will cause postings with a multi-commodity amount (these can+arise when a multi-commodity transaction has an implicit amount) will be+split into multiple single-commodity postings, for valid journal output. -   Normally, transactions' implicit/explicit amount style is preserved:-when an amount is omitted in the journal, it will be omitted in the-output.  You can use the '-x/--explicit' flag to make all amounts-explicit, which can be useful for troubleshooting or for making your-journal more readable and robust against data entry errors.  Note, in-this mode postings with a multi-commodity amount (possible with an-implicit amount in a multi-commodity transaction) will be split into-multiple single-commodity postings, for valid journal output.+   With '-B'/'--cost', amounts with transaction prices are converted to+cost using that price. -   With -B/-cost, amounts with transaction prices are converted to cost-(using the transaction price).+   With '-m'/'--match' and a STR argument, print will show at most one+transaction: the one one whose description is most similar to STR, and+is most recent.  STR should contain at least two characters.  If there+is no similar-enough match, no transaction will be shown. +   With '--new', for each FILE being read, hledger reads (and writes) a+special state file ('.latest.FILE' in the same directory), containing+the latest transaction date(s) that were seen last time FILE was read.+When this file is found, only transactions with newer dates (and new+transactions on the latest date) are printed.  This is useful for+ignoring already-seen entries in import data, such as downloaded CSV+files.  Eg:++$ hledger -f bank1.csv print --new+# shows transactions added since last print --new on this file++   This assumes that transactions added to FILE always have same or+increasing dates, and that transactions on the same day do not get+reordered.  See also the import command.+    The print command also supports output destination and CSV output. Here's an example of print's CSV output: @@ -1680,12 +1810,20 @@      zero or greater amounts under debit.)  -File: hledger.1.info,  Node: register,  Next: stats,  Prev: print,  Up: COMMANDS+File: hledger.1.info,  Node: print-unique,  Next: register,  Prev: print,  Up: COMMANDS -4.12 register+4.16 print-unique+=================++Print transactions which do not reuse an already-seen description.+++File: hledger.1.info,  Node: register,  Next: register-match,  Prev: print-unique,  Up: COMMANDS++4.17 register ============= -Show postings and their running total.  Alias: reg.+Show postings and their running total.  Aliases: r, reg.  '--cumulative' @@ -1787,7 +1925,7 @@  File: hledger.1.info,  Node: Custom register output,  Up: register -4.12.1 Custom register output+4.17.1 Custom register output -----------------------------  register uses the full terminal width by default, except on windows.@@ -1817,9 +1955,27 @@ output.  -File: hledger.1.info,  Node: stats,  Next: test,  Prev: register,  Up: COMMANDS+File: hledger.1.info,  Node: register-match,  Next: rewrite,  Prev: register,  Up: COMMANDS -4.13 stats+4.18 register-match+===================++Print the one posting whose transaction description is closest to DESC,+in the style of the register command.  Helps ledger-autosync detect+already-seen transactions when importing.+++File: hledger.1.info,  Node: rewrite,  Next: stats,  Prev: register-match,  Up: COMMANDS++4.19 rewrite+============++Print all transactions, adding custom postings to the matched ones.+++File: hledger.1.info,  Node: stats,  Next: tags,  Prev: rewrite,  Up: COMMANDS++4.20 stats ==========  Show some journal statistics.@@ -1849,11 +2005,19 @@ output destination.  -File: hledger.1.info,  Node: test,  Prev: stats,  Up: COMMANDS+File: hledger.1.info,  Node: tags,  Next: test,  Prev: stats,  Up: COMMANDS -4.14 test+4.21 tags ========= +List all the tag names in use.+++File: hledger.1.info,  Node: test,  Prev: tags,  Up: COMMANDS++4.22 test+=========+ Run built-in unit tests.  $ hledger test@@ -2006,13 +2170,6 @@ * budget:: * chart:: * check::-* check-dates::-* check-dupes::-* equity::-* prices::-* print-unique::-* register-match::-* rewrite::   File: hledger.1.info,  Node: autosync,  Next: budget,  Up: Experimental add-ons@@ -2042,7 +2199,7 @@ hledger-chart.hs is an old pie chart generator, in need of some love.  -File: hledger.1.info,  Node: check,  Next: check-dates,  Prev: chart,  Up: Experimental add-ons+File: hledger.1.info,  Node: check,  Prev: chart,  Up: Experimental add-ons  5.3.4 check -----------@@ -2050,192 +2207,135 @@ hledger-check.hs checks more powerful account balance assertions.  -File: hledger.1.info,  Node: check-dates,  Next: check-dupes,  Prev: check,  Up: Experimental add-ons--5.3.5 check-dates--------------------hledger-check-dates.hs checks that journal entries are ordered by date.---File: hledger.1.info,  Node: check-dupes,  Next: equity,  Prev: check-dates,  Up: Experimental add-ons--5.3.6 check-dupes--------------------hledger-check-dupes.hs checks for account names sharing the same leaf-name.---File: hledger.1.info,  Node: equity,  Next: prices,  Prev: check-dupes,  Up: Experimental add-ons--5.3.7 equity---------------hledger-equity.hs prints balance-resetting transactions, useful for-bringing account balances across file boundaries.---File: hledger.1.info,  Node: prices,  Next: print-unique,  Prev: equity,  Up: Experimental add-ons--5.3.8 prices---------------hledger-prices.hs prints all prices from the journal.---File: hledger.1.info,  Node: print-unique,  Next: register-match,  Prev: prices,  Up: Experimental add-ons--5.3.9 print-unique---------------------hledger-print-unique.hs prints transactions which do not reuse an-already-seen description.---File: hledger.1.info,  Node: register-match,  Next: rewrite,  Prev: print-unique,  Up: Experimental add-ons--5.3.10 register-match------------------------hledger-register-match.hs helps ledger-autosync detect already-seen-transactions when importing.---File: hledger.1.info,  Node: rewrite,  Prev: register-match,  Up: Experimental add-ons--5.3.11 rewrite-----------------hledger-rewrite.hs Adds one or more custom postings to matched-transactions.-- Tag Table: Node: Top70-Node: EXAMPLES1890-Ref: #examples1992-Node: OPTIONS3638-Ref: #options3742-Node: General options4023-Ref: #general-options4150-Node: Command options6688-Ref: #command-options6841-Node: Command arguments7239-Ref: #command-arguments7399-Node: Special characters7520-Ref: #special-characters7678-Node: Input files8846-Ref: #input-files8984-Node: Smart dates10947-Ref: #smart-dates11090-Node: Report start & end date12069-Ref: #report-start-end-date12241-Node: Report intervals13307-Ref: #report-intervals13472-Node: Period expressions13873-Ref: #period-expressions14033-Node: Depth limiting16373-Ref: #depth-limiting16519-Node: Pivoting16720-Ref: #pivoting16840-Node: Cost18611-Ref: #cost18721-Node: Market value18839-Ref: #market-value18976-Node: Regular expressions20276-Ref: #regular-expressions20414-Node: QUERIES21775-Ref: #queries21879-Node: COMMANDS25544-Ref: #commands25658-Node: accounts26331-Ref: #accounts26431-Node: activity27413-Ref: #activity27525-Node: add27884-Ref: #add27985-Node: balance30643-Ref: #balance30756-Node: Flat mode33771-Ref: #flat-mode33898-Node: Depth limited balance reports34318-Ref: #depth-limited-balance-reports34521-Node: Multicolumn balance reports34941-Ref: #multicolumn-balance-reports35152-Node: Custom balance output39800-Ref: #custom-balance-output39984-Node: Colour support42077-Ref: #colour-support42238-Node: Output destination42411-Ref: #output-destination42569-Node: CSV output42839-Ref: #csv-output42958-Node: balancesheet43355-Ref: #balancesheet43483-Node: cashflow45390-Ref: #cashflow45507-Node: help47375-Ref: #help47487-Node: incomestatement48325-Ref: #incomestatement48455-Node: info50347-Ref: #info50454-Node: man50818-Ref: #man50915-Node: print51320-Ref: #print51425-Node: register55181-Ref: #register55294-Node: Custom register output59790-Ref: #custom-register-output59921-Node: stats61218-Ref: #stats61324-Node: test62205-Ref: #test62292-Node: ADD-ON COMMANDS62660-Ref: #add-on-commands62772-Node: Official add-ons64059-Ref: #official-add-ons64201-Node: api64288-Ref: #api64379-Node: ui64431-Ref: #ui64532-Node: web64590-Ref: #web64681-Node: Third party add-ons64727-Ref: #third-party-add-ons64904-Node: diff65039-Ref: #diff65138-Node: iadd65237-Ref: #iadd65353-Node: interest65436-Ref: #interest65559-Node: irr65654-Ref: #irr65754-Node: Experimental add-ons65832-Ref: #experimental-add-ons65986-Node: autosync66379-Ref: #autosync66493-Node: budget66732-Ref: #budget66856-Node: chart66922-Ref: #chart67041-Node: check67112-Ref: #check67236-Node: check-dates67303-Ref: #check-dates67445-Node: check-dupes67518-Ref: #check-dupes67661-Node: equity67738-Ref: #equity67866-Node: prices67985-Ref: #prices68114-Node: print-unique68169-Ref: #print-unique68318-Node: register-match68411-Ref: #register-match68567-Node: rewrite68665-Ref: #rewrite68786+Node: EXAMPLES1886+Ref: #examples1988+Node: OPTIONS3634+Ref: #options3738+Node: General options4042+Ref: #general-options4169+Node: Command options6488+Ref: #command-options6641+Node: Command arguments7039+Ref: #command-arguments7199+Node: Argument expansion7320+Ref: #argument-expansion7485+Node: Special characters7704+Ref: #special-characters7863+Node: Input files9282+Ref: #input-files9420+Node: Smart dates11383+Ref: #smart-dates11526+Node: Report start & end date12505+Ref: #report-start-end-date12677+Node: Report intervals13743+Ref: #report-intervals13908+Node: Period expressions14309+Ref: #period-expressions14471+Node: Depth limiting16811+Ref: #depth-limiting16957+Node: Pivoting17299+Ref: #pivoting17419+Node: Cost19095+Ref: #cost19205+Node: Market value19323+Ref: #market-value19460+Node: Regular expressions20760+Ref: #regular-expressions20898+Node: QUERIES22259+Ref: #queries22363+Node: COMMANDS26330+Ref: #commands26444+Node: accounts27427+Ref: #accounts27527+Node: activity28520+Ref: #activity28632+Node: add28991+Ref: #add29092+Node: balance31750+Ref: #balance31863+Node: Flat mode35020+Ref: #flat-mode35147+Node: Depth limited balance reports35567+Ref: #depth-limited-balance-reports35770+Node: Multicolumn balance reports36190+Ref: #multicolumn-balance-reports36401+Node: Custom balance output41049+Ref: #custom-balance-output41233+Node: Colour support43326+Ref: #colour-support43487+Node: Output destination43660+Ref: #output-destination43818+Node: CSV output44088+Ref: #csv-output44207+Node: balancesheet44604+Ref: #balancesheet44742+Node: balancesheetequity46710+Ref: #balancesheetequity46861+Node: cashflow47650+Ref: #cashflow47780+Node: check-dates49692+Ref: #check-dates49821+Node: check-dupes49938+Ref: #check-dupes50065+Node: equity50202+Ref: #equity50314+Node: help50477+Ref: #help50580+Node: import51654+Ref: #import51770+Node: incomestatement52165+Ref: #incomestatement52301+Node: prices54254+Ref: #prices54371+Node: print54414+Ref: #print54526+Node: print-unique59372+Ref: #print-unique59500+Node: register59568+Ref: #register59697+Node: Custom register output64198+Ref: #custom-register-output64329+Node: register-match65626+Ref: #register-match65762+Node: rewrite65945+Ref: #rewrite66064+Node: stats66133+Ref: #stats66238+Node: tags67119+Ref: #tags67219+Node: test67251+Ref: #test67337+Node: ADD-ON COMMANDS67705+Ref: #add-on-commands67817+Node: Official add-ons69104+Ref: #official-add-ons69246+Node: api69333+Ref: #api69424+Node: ui69476+Ref: #ui69577+Node: web69635+Ref: #web69726+Node: Third party add-ons69772+Ref: #third-party-add-ons69949+Node: diff70084+Ref: #diff70183+Node: iadd70282+Ref: #iadd70398+Node: interest70481+Ref: #interest70604+Node: irr70699+Ref: #irr70799+Node: Experimental add-ons70877+Ref: #experimental-add-ons71031+Node: autosync71322+Ref: #autosync71436+Node: budget71675+Ref: #budget71799+Node: chart71865+Ref: #chart71984+Node: check72055+Ref: #check72159  End Tag Table
doc/hledger.1.txt view
@@ -111,19 +111,12 @@ OPTIONS    General options        To see general usage help, including general  options  which  are  sup--       ported  by  most hledger commands, run hledger -h.  (Note -h and --help-       are different, like git.)+       ported by most hledger commands, run hledger -h.         General help options: -       -h     show general usage (or after COMMAND, command usage)--       --help show this program's manual as plain text  (or  after  an  add-on-              COMMAND, the add-on's manual)--       --man  show this program's manual with man--       --info show this program's manual with info+       -h --help+              show general usage (or after COMMAND, command usage)         --version               show version@@ -146,8 +139,8 @@         --anon anonymize accounts and payees -       --pivot TAGNAME-              use some other field/tag for account names+       --pivot FIELDNAME+              use some other field or tag for the account name         -I --ignore-assertions               ignore any failing balance assertions@@ -180,7 +173,8 @@               (overrides the flags above)         --date2-              show, and match with -b/-e/-p/date:, secondary dates instead+              match the secondary date instead (see  command  help  for  other+              effects)         -U --unmarked               include only unmarked postings/txns (can combine with -P or -C)@@ -194,58 +188,69 @@        -R --real               include only non-virtual postings -       --depth=N-              hide accounts/postings deeper than N+       -NUM --depth=NUM+              hide/aggregate accounts or postings more than NUM levels deep         -E --empty               show items with zero amount, normally hidden         -B --cost-              convert amounts to their cost at  transaction  time  (using  the+              convert  amounts  to  their  cost at transaction time (using the               transaction price, if any)         -V --value-              convert  amounts  to  their  market value on the report end date+              convert amounts to their market value on  the  report  end  date               (using the most recent applicable market price, if any) -       Note when multiple similar reporting options are provided, the last one-       takes precedence.  Eg -p feb -p mar is equivalent to -p mar.+       When a reporting option appears more than once in the command line, the+       last one takes precedence. -       Some of these can also be written as queries.+       Some reporting options can also be written as query arguments.     Command options-       To  see  options  for  a particular command, including command-specific+       To see options for a  particular  command,  including  command-specific        options, run: hledger COMMAND -h. -       Command-specific options must be written after the  command  name,  eg:+       Command-specific  options  must  be written after the command name, eg:        hledger print -x. -       Additionally,  if  the  command  is  an  addon, you may need to put its-       options after a double-hyphen, eg: hledger ui -- --watch.  Or, you  can+       Additionally, if the command is an addon,  you  may  need  to  put  its+       options  after a double-hyphen, eg: hledger ui -- --watch.  Or, you can        run the addon executable directly: hledger-ui --watch.     Command arguments-       Most  hledger  commands  accept arguments after the command name, which+       Most hledger commands accept arguments after the  command  name,  which        are often a query, filtering the data in some way. +   Argument expansion+       You can save a set of command line options/arguments in a file, one per+       line, and then reuse them by writing @FILE in a command line.  (To pre-+       vent this expansion of @-arguments, precede them with a -- argument.)+    Special characters-       Option and argument values which contain problematic characters  should-       be  escaped  with  double quotes, backslashes, or (best) single quotes.+       Option  and argument values which contain problematic characters should+       be escaped with double quotes, backslashes, or  (best)  single  quotes.        Problematic characters means spaces, and also characters which are sig--       nificant  to  your  command shell, such as less-than/greater-than.  Eg:+       nificant to your command shell, such  as  less-than/greater-than.   Eg:        hledger register -p 'last year' "accounts receivable (receiv-        able|payable)" amt:\>100. -       Characters  which  are  significant  both  to  the shell and in regular-       expressions sometimes need to be double-escaped.  These include  paren--       theses,  the  pipe symbol and the dollar sign.  Eg, to match the dollar-       symbol, bash users should do: hledger balance cur:'\$' or  hledger bal-+       Characters which are significant both  to  the  shell  and  in  regular+       expressions  sometimes need to be double-escaped.  These include paren-+       theses, the pipe symbol and the dollar sign.  Eg, to match  the  dollar+       symbol,  bash users should do: hledger balance cur:'\$' or hledger bal-        ance cur:\\$. -       There's  more..   options  and arguments get de-escaped when hledger is-       passing them to an addon executable.   In  this  case  you  might  need-       triple-escaping.  Eg: hledger ui cur:'\\$' or hledger ui cur:\\\\$.+       When hledger is invoking an addon executable (like hledger-ui), options+       and arguments get de-escaped once more, so you might need triple-escap-+       ing.  Eg: hledger ui cur:'\\$' or hledger ui cur:\\\\$ in  bash.   (The+       number  of  backslashes  in  fish  shell is left as an exercise for the+       reader.) +       Inside a file used for argument expansion, one less level  of  escaping+       is  enough.   (And  in  this case, backslashes seem to work better than+       quotes.  Eg: cur:\$).+        If in doubt, keep things simple:         o run add-on executables directly@@ -261,7 +266,7 @@    Input files        hledger reads transactions from a data file (and the add command writes        to it).  By default this file is $HOME/.hledger.journal (or on Windows,-       something  like C:/Users/USER/.hledger.journal).  You can override this+       something like C:/Users/USER/.hledger.journal).  You can override  this        with the $LEDGER_FILE environment variable:                $ setenv LEDGER_FILE ~/finance/2016.journal@@ -275,9 +280,9 @@                $ cat some.journal | hledger -f- -       Usually the data file is in hledger's journal format, but it  can  also-       be  one  of  several  other formats, listed below.  hledger detects the-       format automatically based on the file extension, or  if  that  is  not+       Usually  the  data file is in hledger's journal format, but it can also+       be one of several other formats, listed  below.   hledger  detects  the+       format  automatically  based  on  the file extension, or if that is not        recognised, by trying each built-in "reader" in turn:  @@ -285,15 +290,15 @@        -----------------------------------------------------------------------------        journal       hledger's  journal  format,  also   .journal    .j    .hledger                      some Ledger journals                .ledger-       timeclock     timeclock   files  (precise  time   .timeclock+       timeclock     timeclock  files  (precise   time   .timeclock                      logging)-       timedot       timedot files  (approximate  time   .timedot+       timedot       timedot  files  (approximate time   .timedot                      logging)-       csv           comma-separated    values   (data   .csv+       csv           comma-separated   values    (data   .csv                      interchange) -       If needed (eg to ensure correct error messages  when  a  file  has  the-       "wrong"  extension), you can force a specific reader/format by prepend-+       If  needed  (eg  to  ensure  correct error messages when a file has the+       "wrong" extension), you can force a specific reader/format by  prepend-        ing it to the file path with a colon.  Examples:                $ hledger -f csv:/some/csv-file.dat stats@@ -304,7 +309,7 @@         o directives in one file will not affect the other files -       o balance  assertions  will  not see any account balances from previous+       o balance assertions will not see any account  balances  from  previous          files         If you need those, either use the include directive, or concatenate the@@ -312,8 +317,8 @@     Smart dates        hledger's user interfaces accept a flexible "smart date" syntax (unlike-       dates in the journal file).  Smart dates allow some english words,  can-       be  relative  to today's date, and can have less-significant date parts+       dates  in the journal file).  Smart dates allow some english words, can+       be relative to today's date, and can have less-significant  date  parts        omitted (defaulting to 1).         Examples:@@ -321,14 +326,15 @@         2009/1/1,      2009/01/01,   simple dates, several sep-        2009-1-1, 2009.1.1           arators allowed-       2009/1, 2009                 same as above - a  missing+       2009/1, 2009                 same  as above - a missing                                     day or month defaults to 1-       1/1,     january,     jan,   relative   dates,  meaning-       this year                    january 1 of  the  current+       1/1,     january,     jan,   relative  dates,   meaning+       this year                    january  1  of the current                                     year        next year                    january 1 of next year        this month                   the  1st  of  the  current                                     month+        this week                    the most recent monday        last week                    the  monday  of  the  week                                     before this one@@ -336,16 +342,16 @@        today, yesterday, tomorrow     Report start & end date-       Most hledger reports show the full span  of  time  represented  by  the+       Most  hledger  reports  show  the  full span of time represented by the        journal data, by default.  So, the effective report start and end dates-       will be the earliest and latest transaction or posting dates  found  in+       will  be  the earliest and latest transaction or posting dates found in        the journal. -       Often  you  will  want  to see a shorter time span, such as the current-       month.  You can specify a  start  and/or  end  date  using  -b/--begin,+       Often you will want to see a shorter time span,  such  as  the  current+       month.   You  can  specify  a  start  and/or end date using -b/--begin,        -e/--end, -p/--period or a date: query (described below).  All of these-       accept the smart date syntax.  One important thing to be aware of  when-       specifying  end  dates:  as  in Ledger, end dates are exclusive, so you+       accept  the smart date syntax.  One important thing to be aware of when+       specifying end dates: as in Ledger, end dates  are  exclusive,  so  you        need to write the date after the last day you want to include.         Examples:@@ -355,10 +361,10 @@                          day 2016        -e 12/1           end at the start of decem-                          ber  1st  of  the  current-                         year  (11/30  will  be the+                         year (11/30  will  be  the                          last date included)-       -b thismonth      all  transactions  on   or-                         after  the 1st of the cur-+       -b thismonth      all   transactions  on  or+                         after the 1st of the  cur-                          rent month        -p thismonth      all  transactions  in  the                          current month@@ -370,24 +376,24 @@     Report intervals        A report interval can be specified so that commands like register, bal--       ance  and  activity will divide their reports into multiple subperiods.-       The  basic  intervals  can  be  selected  with   one   of   -D/--daily,-       -W/--weekly,  -M/--monthly,  -Q/--quarterly, or -Y/--yearly.  More com--       plex intervals may be  specified  with  a  period  expression.   Report+       ance and activity will divide their reports into  multiple  subperiods.+       The   basic   intervals   can  be  selected  with  one  of  -D/--daily,+       -W/--weekly, -M/--monthly, -Q/--quarterly, or -Y/--yearly.   More  com-+       plex  intervals  may  be  specified  with  a period expression.  Report        intervals can not be specified with a query, currently.     Period expressions-       The  -p/--period  option accepts period expressions, a shorthand way of-       expressing a start date, end date, and/or report interval all at  once.+       The -p/--period option accepts period expressions, a shorthand  way  of+       expressing  a start date, end date, and/or report interval all at once. -       Here's  a basic period expression specifying the first quarter of 2009.-       Note, hledger always treats start dates as inclusive and end  dates  as+       Here's a basic period expression specifying the first quarter of  2009.+       Note,  hledger  always treats start dates as inclusive and end dates as        exclusive:         -p "from 2009/1/1 to 2009/4/1" -       Keywords  like  "from" and "to" are optional, and so are the spaces, as-       long as you don't run two dates together.  "to" can also be written  as+       Keywords like "from" and "to" are optional, and so are the  spaces,  as+       long  as you don't run two dates together.  "to" can also be written as        "-".  These are equivalent to the above:  @@ -395,7 +401,7 @@        -p2009/1/1to2009/4/1        -p2009/1/1-2009/4/1 -       Dates  are  smart  dates, so if the current year is 2009, the above can+       Dates are smart dates, so if the current year is 2009,  the  above  can        also be written as:  @@ -411,25 +417,25 @@                             1, 2009        -p "from 2009/1"     the same        -p "from 2009"       the same-       -p "to 2009"         everything before  january+       -p "to 2009"         everything  before january                             1, 2009 -       A  single  date  with  no "from" or "to" defines both the start and end+       A single date with no "from" or "to" defines both  the  start  and  end        date like so:  -       -p "2009"       the year 2009;  equivalent+       -p "2009"       the  year 2009; equivalent                        to "2009/1/1 to 2010/1/1"-       -p "2009/1"     the  month of jan; equiva-+       -p "2009/1"     the month of jan;  equiva-                        lent   to   "2009/1/1   to                        2009/2/1"-       -p "2009/1/1"   just  that day; equivalent+       -p "2009/1/1"   just that day;  equivalent                        to "2009/1/1 to 2009/1/2" -       The argument of -p can also  begin  with,  or  be,  a  report  interval-       expression.   The  basic  report  intervals are daily, weekly, monthly,+       The  argument  of  -p  can  also  begin  with, or be, a report interval+       expression.  The basic report intervals  are  daily,  weekly,  monthly,        quarterly, or yearly, which have the same effect as the -D,-W,-M,-Q, or-       -Y  flags.   Between  report interval and start/end dates (if any), the+       -Y flags.  Between report interval and start/end dates  (if  any),  the        word in is optional.  Examples:  @@ -438,7 +444,7 @@        -p "quarterly"         The  following  more  complex  report  intervals  are  also  supported:-       biweekly,      bimonthly,     every N days|weeks|months|quarters|years,+       biweekly,     bimonthly,      every N days|weeks|months|quarters|years,        every Nth day [of month], every Nth day of week.         Examples:@@ -448,35 +454,34 @@        -p "every 2 weeks"        -p "every 5 days from 1/3" -       Show historical balances at end of 15th each month (N is exclusive  end+       Show  historical balances at end of 15th each month (N is exclusive end        date):         hledger balance -H -p "every 16th day" -       Group  postings  from  start  of wednesday to end of next tuesday (N is+       Group postings from start of wednesday to end of  next  tuesday  (N  is        start date and exclusive end date):         hledger register checking -p "every 3rd day of week"     Depth limiting-       With the --depth N option, commands like account, balance and  register-       will  show  only  the  uppermost  accounts in the account tree, down to-       level N.  Use this when you want a summary with less detail.+       With the --depth N option (short form: -N), commands like account, bal-+       ance and register will show only the uppermost accounts in the  account+       tree,  down  to  level  N.   Use this when you want a summary with less+       detail.  This flag has the same effect as a depth: query  argument  (so+       -2, --depth=2 or depth:2 are basically equivalent).     Pivoting        Normally hledger sums amounts, and organizes them in a hierarchy, based-       on account name.  The --pivot TAGNAME option causes it to sum and orga--       nize hierarchy based on some other field instead.--       TAGNAME is the full, case-insensitive name of a tag you  have  defined,-       or  one  of  the  built-in implicit tags (like code or payee).  As with-       account names,  when  tag  values  have  multiple:colon-separated:parts-       hledger will build hierarchy, displayed in tree-mode reports, summaris--       able with a depth limit, and so on.+       on account name.  The --pivot FIELD option causes it to sum  and  orga-+       nize  hierarchy  based on the value of some other field instead.  FIELD+       can be: code, description, payee, note, or the full name (case insensi-+       tive) of any tag.  As with account names, values containing colon:sepa-+       rated:parts will be displayed hierarchically in reports.         --pivot is a general option affecting all reports;  you  can  think  of        hledger transforming the journal before any other processing, replacing-       every posting's account name with the value of  the  specified  tag  on+       every posting's account name with the value of the specified  field  on        that posting, inheriting it from the transaction or using a blank value        if it's not present. @@ -613,11 +618,12 @@        sion,  written  as arguments after the command name, to filter the data        by date, account name or other criteria.  The syntax is  similar  to  a        web search: one or more space-separated search terms, quotes to enclose-       whitespace, optional  prefixes  to  match  specific  fields.   Multiple-       search terms are combined as follows:+       whitespace, prefixes to match specific fields, a not: prefix to  negate+       the match. -       All  commands  except  print: show transactions/postings/accounts which-       match (or negatively match)+       We  do  not yet support arbitrary boolean combinations of search terms;+       instead most commands show transactions/postings/accounts  which  match+       (or negatively match):         o any of the description terms AND @@ -627,7 +633,7 @@         o all the other terms. -       The print command: show transactions which+       The print command instead shows transactions which:         o match any of the description terms AND @@ -637,50 +643,60 @@         o match all the other terms. -       The following kinds of search terms can be used:+       The  following  kinds  of search terms can be used.  Remember these can+       also be prefixed with not:, eg to exclude a particular subaccount. -       REGEX  match account names by this regular expression+       REGEX  match account names by this regular expression.  (No  prefix  is+              equivalent to acct:).         acct:REGEX               same as above         amt:N, amt:<N, amt:<=N, amt:>N, amt:>=N-              match postings with a single-commodity amount that is equal  to,-              less  than, or greater than N.  (Multi-commodity amounts are not+              match  postings with a single-commodity amount that is equal to,+              less than, or greater than N.  (Multi-commodity amounts are  not               tested, and will always match.) The comparison has two modes: if               N is preceded by a + or - sign (or is 0), the two signed numbers-              are compared.  Otherwise, the absolute magnitudes are  compared,+              are  compared.  Otherwise, the absolute magnitudes are compared,               ignoring sign.         code:REGEX               match by transaction code (eg check number)         cur:REGEX-              match  postings or transactions including any amounts whose cur--              rency/commodity symbol is fully matched by REGEX.  (For  a  par-+              match postings or transactions including any amounts whose  cur-+              rency/commodity  symbol  is fully matched by REGEX.  (For a par-               tial match, use .*REGEX.*).  Note, to match characters which are               regex-significant, like the dollar sign ($), you need to prepend-              \.   And  when  using  the command line you need to add one more+              \.  And when using the command line you need  to  add  one  more               level  of  quoting  to  hide  it  from  the  shell,  so  eg  do:               hledger print cur:'\$' or hledger print cur:\\$.         desc:REGEX-              match transaction descriptions+              match transaction descriptions.         date:PERIODEXPR               match dates within the specified period.  PERIODEXPR is a period-              expression (with  no  report  interval).   Examples:  date:2016,-              date:thismonth,   date:2000/2/1-2/15,  date:lastweek-.   If  the-              --date2 command line flag is  present,  this  matches  secondary+              expression  (with  no  report  interval).   Examples: date:2016,+              date:thismonth,  date:2000/2/1-2/15,  date:lastweek-.   If   the+              --date2  command  line  flag  is present, this matches secondary               dates instead.         date2:PERIODEXPR               match secondary dates within the specified period.         depth:N-              match  (or  display,  depending on command) accounts at or above+              match (or display, depending on command) accounts  at  or  above               this depth +       note:REGEX+              match  transaction  notes  (part  of  description right of |, or+              whole description when there's no |)++       payee:REGEX+              match transaction payee/payer names (part of description left of+              |, or whole description when there's no |)+        real:, real:0               match real or virtual postings respectively @@ -688,40 +704,42 @@               match unmarked, pending, or cleared transactions respectively         tag:REGEX[=REGEX]-              match by tag name, and optionally also by  tag  value.   Note  a-              tag:  query  is  considered to match a transaction if it matches-              any of the postings.  Also remember that  postings  inherit  the+              match  by  tag  name,  and optionally also by tag value.  Note a+              tag: query is considered to match a transaction  if  it  matches+              any  of  the  postings.  Also remember that postings inherit the               tags of their parent transaction. -       not:   before any of the above negates the match.+       The following special search term is used automatically in hledger-web,+       only:         inacct:ACCTNAME-              a special term used automatically when you click an account name-              in hledger-web, specifying the account register we are currently-              in  (selects  the  transactions  of that account and how to show-              them, can be filtered further with  acct  etc).   Not  supported-              elsewhere in hledger.+              tells  hledger-web  to  show  the  transaction register for this+              account.  Can be filtered further with acct etc.         Some of these can also be expressed as command-line options (eg depth:2-       is equivalent to --depth 2).  Generally you can mix options  and  query-       arguments,  and the resulting query will be their intersection (perhaps+       is  equivalent  to --depth 2).  Generally you can mix options and query+       arguments, and the resulting query will be their intersection  (perhaps        excluding the -p/--period option).  COMMANDS-       hledger provides a number of subcommands;  hledger  with  no  arguments+       hledger  provides  a  number  of subcommands; hledger with no arguments        shows a list.         If you install additional hledger-* packages, or if you put programs or-       scripts named hledger-NAME in your PATH, these will also be  listed  as+       scripts  named  hledger-NAME in your PATH, these will also be listed as        subcommands. -       Run   a   subcommand   by  writing  its  name  as  first  argument  (eg-       hledger incomestatement).  You can also write any unambiguous prefix of-       a command name (hledger inc), or one of the standard short aliases dis--       played in the command list (hledger is).+       Run  a  subcommand  by  writing  its  name  as   first   argument   (eg+       hledger incomestatement).  You can also write one of the standard short+       aliases displayed in parentheses in the command  list  (hledger b),  or+       any any unambiguous prefix of a command name (hledger inc). +       Here  are  all  the  builtin  commands in alphabetical order.  See also+       hledger for a more  organised  command  list,  and  hledger CMD -h  for+       detailed command help.+    accounts-       Show account names.+       Show account names.  Alias: a.         --tree show short account names, as a tree @@ -730,14 +748,14 @@        --drop=N               in flat mode: omit N leading account name parts -       This command lists all account names that  are  in  use  (ie,  all  the-       accounts  which  have  at least one transaction posting to them).  With+       This  command  lists  all  account  names  that are in use (ie, all the+       accounts which have at least one transaction posting  to  them).   With        query arguments, only matched account names are shown. -       It shows a flat list by default.  With --tree, it uses  indentation  to+       It  shows  a flat list by default.  With --tree, it uses indentation to        show the account hierarchy. -       In  flat  mode  you can add --drop N to omit the first few account name+       In flat mode you can add --drop N to omit the first  few  account  name        components.         Examples:@@ -780,8 +798,8 @@    activity        Show an ascii barchart of posting counts per interval. -       The activity command displays an ascii  histogram  showing  transaction-       counts  by  day, week, month or other reporting interval (by day is the+       The  activity  command  displays an ascii histogram showing transaction+       counts by day, week, month or other reporting interval (by day  is  the        default).  With query arguments, it counts only matched transactions.                $ hledger activity --quarterly@@ -794,24 +812,24 @@        Prompt for transactions and add them to the journal.         --no-new-accounts-              don't allow creating new  accounts;  helps  prevent  typos  when+              don't  allow  creating  new  accounts;  helps prevent typos when               entering account names -       Many  hledger users edit their journals directly with a text editor, or-       generate them from CSV.  For more interactive data entry, there is  the-       add  command, which prompts interactively on the console for new trans--       actions, and appends them to the journal file (if  there  are  multiple+       Many hledger users edit their journals directly with a text editor,  or+       generate  them from CSV.  For more interactive data entry, there is the+       add command, which prompts interactively on the console for new  trans-+       actions,  and  appends  them to the journal file (if there are multiple        -f FILE options, the first file is used.) Existing transactions are not-       changed.  This is the only hledger command that writes to  the  journal+       changed.   This  is the only hledger command that writes to the journal        file.         To use it, just run hledger add and follow the prompts.  You can add as-       many transactions as you like; when you are finished, enter . or  press+       many  transactions as you like; when you are finished, enter . or press        control-d or control-c to exit.         Features: -       o add  tries  to provide useful defaults, using the most similar recent+       o add tries to provide useful defaults, using the most  similar  recent          transaction (by description) as a template.         o You can also set the initial defaults with command line arguments.@@ -819,20 +837,20 @@        o Readline-style edit keys can be used during data entry.         o The tab key will auto-complete whenever possible - accounts, descrip--         tions,  dates  (yesterday,  today,  tomorrow).   If the input area is+         tions, dates (yesterday, today, tomorrow).   If  the  input  area  is          empty, it will insert the default value. -       o If the journal defines a default commodity, it will be added  to  any+       o If  the  journal defines a default commodity, it will be added to any          bare numbers entered.         o A parenthesised transaction code may be entered following a date.         o Comments and tags may be entered following a description or amount. -       o If  you make a mistake, enter < at any prompt to restart the transac-+       o If you make a mistake, enter < at any prompt to restart the  transac-          tion. -       o Input prompts are displayed in a different colour when  the  terminal+       o Input  prompts  are displayed in a different colour when the terminal          supports it.         Example (see the tutorial for a detailed explanation):@@ -863,13 +881,13 @@               Date [2015/05/22]: <CTRL-D> $     balance-       Show accounts and their balances.  Alias: bal.+       Show accounts and their balances.  Aliases: b, bal.         --change               show balance change in each period (default)         --cumulative-              show  balance  change accumulated across periods (in multicolumn+              show balance change accumulated across periods  (in  multicolumn               reports)         -H --historical@@ -904,12 +922,16 @@               select the output format.  Supported formats: txt, csv.         -o FILE --output-file=FILE-              write  output  to  FILE.   A  file extension matching one of the+              write output to FILE.  A file  extension  matching  one  of  the               above formats selects that format.         --pretty-tables               Use unicode to display prettier tables. +       --sort-amount+              Sort  by amount (total row amount, or by average if that is dis-+              played), instead of account name (in flat mode)+        The balance command displays accounts and balances.   It  is  hledger's        most featureful and versatile command. @@ -1198,6 +1220,9 @@        --format=LINEFORMAT               in single-column balance reports: use this custom line format +       --sort-amount+              sort by amount instead of account name+        This  command  displays  a  simple balance sheet.  It currently assumes        that you have top-level accounts  named  asset  and  liability  (plural        forms also allowed.)@@ -1227,6 +1252,41 @@        ancesheet shows historical ending balances, which is what you need  for        a balance sheet; note this means it ignores report begin dates. +   balancesheetequity+       Show a balance sheet including equity.  Alias: bse.++       Other  than  showing  the  equity accounts, this command is exactly the+       same as the command balancesheet.  Please refer to it for the available+       options.++       This  command  displays  a balancesheet.  It currently assumes that you+       have top-level accounts named asset, liability and equity (plural forms+       also allowed.)++              $ hledger balancesheetequity+              Balance Sheet With Equity++              Assets:+                               $-2  assets+                                $1    bank:saving+                               $-3    cash+              --------------------+                               $-2++              Liabilities:+                                $1  liabilities:debts+              --------------------+                                $1++              Equity:+                        $1  equity:owner+              --------------------+                        $1++              Total:+              --------------------+                                 0+    cashflow        Show a cashflow statement.  Alias: cf. @@ -1265,10 +1325,13 @@        --format=LINEFORMAT               in single-column balance reports: use this custom line format +       --sort-amount+              sort by amount instead of account name+        This command displays a simple cashflow statement It shows  the  change        in  all  "cash"  (ie,  liquid assets) accounts for the period.  It cur-        rently assumes that cash accounts are under a top-level  account  named-       asset and do not contain receivable or A/R (plural forms also allowed.)+       asset and do not contain receivable, :A/R or :fixed.                $ hledger cashflow               Cashflow Statement@@ -1285,38 +1348,69 @@                                $-1         With a reporting interval, multiple columns will be shown, one for each-       report  period.   Normally cashflow shows changes in assets per period,-       though as with multicolumn balance reports you  can  alter  the  report+       report period.  Normally cashflow shows changes in assets  per  period,+       though  as  with  multicolumn  balance reports you can alter the report        mode with --change/--cumulative/--historical. +   check-dates+       Check that transactions are sorted by increasing date.  With  a  query,+       only matched transactions' dates are checked.++   check-dupes+       Report  account  names having the same leaf but different prefixes.  An+       example: http://stefanorodighiero.net/software/hledger-dupes.html++   equity+       Print closing/opening transactions that bring some or all account  bal-+       ances  to  zero  and back.  Can be useful for bringing account balances+       across file boundaries.+    help        Show any of the hledger manuals. -       The  help  command displays any of the main hledger man pages.  (Unlike-       hledger --help, which displays only the hledger man page.) Run it  with-       no  arguments  to  list available topics (their names are shortened for-       easier typing), and run hledger help TOPIC to select one.   The  output-       is  similar to a man page, but fixed width.  It may be long, so you may-       wish to pipe it into a pager.  See also info and man.--              $ hledger help-              Choose a topic, eg: hledger help cli-              cli, ui, web, api, journal, csv, timeclock, timedot+       The help command displays any of the main hledger manuals,  in  one  of+       several  ways.  Run it with no argument to list the manuals, or provide+       a full or partial manual name to select one. -              $ hledger help cli | less+       hledger manuals are available in several formats.   hledger  help  will+       use  the  first  of  these  display  methods  that it finds: info, man,+       $PAGER, less, stdout (or when non-interactive, just stdout).   You  can+       force a particular viewer with the --info, --man, --pager, --cat flags. -              hledger(1)                   hledger User Manuals                   hledger(1)+              $ hledger help+              Please choose a manual by typing "hledger help MANUAL" (a substring is ok).+              Manuals: hledger hledger-ui hledger-web hledger-api journal csv timeclock timedot +              $ hledger help h --man +              hledger(1)                    hledger User Manuals                    hledger(1)                NAME                      hledger - a command-line accounting tool                SYNOPSIS-                     hledger [-f FILE] COMMAND [OPTIONS] [CMDARGS]-                     hledger [-f FILE] ADDONCMD -- [OPTIONS] [CMDARGS]-              :+                     hledger [-f FILE] COMMAND [OPTIONS] [ARGS]+                     hledger [-f FILE] ADDONCMD -- [OPTIONS] [ARGS]+                     hledger +              DESCRIPTION+                     hledger  is  a  cross-platform  program  for tracking money, time, or any+              ...++   import+       Read new transactions added to each FILE since last run, and  add  them+       to the main journal file.++       --dry-run+              just show the transactions to be imported++       Input  files are provided as arguments, or glob patterns.  So eg to add+       new transactions from all CSV files to the main journal: hledger import+       *.csv++       New  transactions  are  detected  like  print --new (using .latest.FILE+       state files).+    incomestatement        Show an income statement.  Alias: is. @@ -1355,6 +1449,9 @@        --format=LINEFORMAT               in single-column balance reports: use this custom line format +       --sort-amount+              sort by amount instead of account name+        This  command displays a simple income statement.  It currently assumes        that you have top-level accounts named income (or revenue) and  expense        (plural forms also allowed.)@@ -1385,43 +1482,27 @@        period,  though  as  with multicolumn balance reports you can alter the        report mode with --change/--cumulative/--historical. -   info-       Show any of the hledger manuals using info.--       The info command displays any of the hledger  reference  manuals  using-       the  info  hypertextual documentation viewer.  This can be a very effi--       cient way to browse large manuals.  It requires the "info"  program  to-       be available in your PATH.--       As  with help, run it with no arguments to list available topics (manu--       als).--   man-       Show any of the hledger manuals using man.--       The man command displays any of the  hledger  reference  manuals  using-       man,  the standard documentation viewer on unix systems.  This will fit-       the text to your terminal width, and probably invoke a pager  automati--       cally.  It requires the "man" program to be available in your PATH.--       As  with help, run it with no arguments to list available topics (manu--       als).+   prices+       Print all market prices from the journal.     print-       Show transactions from the journal.--       -x     --explicit-              show all amounts explicitly+       Show transactions from the journal.  Aliases: p, txns.         -m STR --match=STR               show the transaction whose description is most similar  to  STR,               and is most recent +       --new  show only newer-dated transactions added in each file since last+              run++       -x     --explicit+              show all amounts explicitly+        -O FMT --output-format=FMT               select the output format.  Supported formats: txt, csv.         -o FILE --output-file=FILE-              write  output  to  FILE.   A  file extension matching one of the+              write output to FILE.  A file  extension  matching  one  of  the               above formats selects that format.                $ hledger print@@ -1447,25 +1528,44 @@                   assets:bank:checking           $-1         The print command displays full journal entries (transactions) from the-       journal file, tidily formatted.--       As  of  hledger  1.2, print's output is always a valid hledger journal.-       However it may not preserve all original content, eg it does not  print-       directives or inter-transaction comments.+       journal file in date order, tidily formatted.  print's output is always+       a valid hledger journal.  It preserves all transaction information, but+       it does not preserve directives or inter-transaction comments -       Normally,  transactions'  implicit/explicit  amount style is preserved:-       when an amount is omitted in the journal, it will  be  omitted  in  the-       output.   You  can  use  the  -x/--explicit  flag  to  make all amounts-       explicit, which can be useful for troubleshooting or  for  making  your-       journal  more  readable and robust against data entry errors.  Note, in-       this mode postings with a  multi-commodity  amount  (possible  with  an-       implicit  amount  in  a multi-commodity transaction) will be split into-       multiple single-commodity postings, for valid journal output.+       Normally, the journal entry's explicit or implicit amount style is pre-+       served.   Ie when an amount is omitted in the journal, it will be omit-+       ted in the output.  You can use the  -x/--explicit  flag  to  make  all+       amounts explicit, which can be useful for troubleshooting or for making+       your journal more readable and robust against data entry errors.  Note,+       -x  will  cause postings with a multi-commodity amount (these can arise+       when a multi-commodity transaction has  an  implicit  amount)  will  be+       split  into  multiple single-commodity postings, for valid journal out-+       put.         With -B/--cost, amounts with transaction prices are converted  to  cost-       (using the transaction price).+       using that price. -       The  print  command  also  supports  output destination and CSV output.+       With  -m/--match and a STR argument, print will show at most one trans-+       action: the one one whose description is most similar to  STR,  and  is+       most  recent.  STR should contain at least two characters.  If there is+       no similar-enough match, no transaction will be shown.++       With --new, for each FILE being read, hledger reads (and writes) a spe-+       cial  state  file  (.latest.FILE in the same directory), containing the+       latest transaction date(s) that were seen  last  time  FILE  was  read.+       When  this  file  is found, only transactions with newer dates (and new+       transactions on the latest date)  are  printed.   This  is  useful  for+       ignoring  already-seen  entries  in import data, such as downloaded CSV+       files.  Eg:++              $ hledger -f bank1.csv print --new+              # shows transactions added since last print --new on this file++       This assumes that transactions  added  to  FILE  always  have  same  or+       increasing  dates,  and  that  transactions  on the same day do not get+       reordered.  See also the import command.++       The print command also supports  output  destination  and  CSV  output.        Here's an example of print's CSV output:                $ hledger print -Ocsv@@ -1482,30 +1582,33 @@               "5","2008/12/31","","*","","pay off","","liabilities:debts","1","$","","1","",""               "5","2008/12/31","","*","","pay off","","assets:bank:checking","-1","$","1","","","" -       o There is one CSV record per posting, with  the  parent  transaction's+       o There  is  one  CSV record per posting, with the parent transaction's          fields repeated.         o The "txnidx" (transaction index) field shows which postings belong to-         the same transaction.  (This number might change if transactions  are-         reordered  within  the file, files are parsed/included in a different+         the  same transaction.  (This number might change if transactions are+         reordered within the file, files are parsed/included in  a  different          order, etc.) -       o The amount is separated into "commodity" (the  symbol)  and  "amount"+       o The  amount  is  separated into "commodity" (the symbol) and "amount"          (numeric quantity) fields.         o The numeric amount is repeated in either the "credit" or "debit" col--         umn, for convenience.  (Those names are not accurate in the  account--         ing  sense;  it  just  puts negative amounts under credit and zero or+         umn,  for convenience.  (Those names are not accurate in the account-+         ing sense; it just puts negative amounts under  credit  and  zero  or          greater amounts under debit.) +   print-unique+       Print transactions which do not reuse an already-seen description.+    register-       Show postings and their running total.  Alias: reg.+       Show postings and their running total.  Aliases: r, reg.         --cumulative               show running total from report start date (default)         -H --historical-              show historical running total/balance (includes postings  before+              show  historical running total/balance (includes postings before               report start date)         -A --average@@ -1516,18 +1619,18 @@               show postings' siblings instead         -w N --width=N-              set output width (default: terminal  width  or  COLUMNS.   -wN,M+              set  output  width  (default:  terminal width or COLUMNS.  -wN,M               sets description width as well)         -O FMT --output-format=FMT               select the output format.  Supported formats: txt, csv.         -o FILE --output-file=FILE-              write  output  to  FILE.   A  file extension matching one of the+              write output to FILE.  A file  extension  matching  one  of  the               above formats selects that format.         The register command displays postings, one per line, and their running-       total.   This  is  typically  used  with a query selecting a particular+       total.  This is typically used with  a  query  selecting  a  particular        account, to see that account's activity:                $ hledger register checking@@ -1536,8 +1639,8 @@               2008/06/02 save                 assets:bank:checking           $-1            $1               2008/12/31 pay off              assets:bank:checking           $-1             0 -       The --historical/-H flag adds the balance from  any  undisplayed  prior-       postings  to  the  running  total.  This is useful when you want to see+       The  --historical/-H  flag  adds the balance from any undisplayed prior+       postings to the running total.  This is useful when  you  want  to  see        only recent activity, with a historically accurate running balance:                $ hledger register checking -b 2008/6 --historical@@ -1547,23 +1650,23 @@         The --depth option limits the amount of sub-account detail displayed. -       The --average/-A flag shows the running average posting amount  instead+       The  --average/-A flag shows the running average posting amount instead        of the running total (so, the final number displayed is the average for-       the whole report period).  This flag implies --empty (see  below).   It-       is  affected  by  --historical.   It  works  best when showing just one+       the  whole  report period).  This flag implies --empty (see below).  It+       is affected by --historical.  It  works  best  when  showing  just  one        account and one commodity. -       The --related/-r flag shows the other postings in the  transactions  of+       The  --related/-r  flag shows the other postings in the transactions of        the postings which would normally be shown. -       With  a  reporting  interval,  register shows summary postings, one per+       With a reporting interval, register shows  summary  postings,  one  per        interval, aggregating the postings to each account:                $ hledger register --monthly income               2008/01                 income:salary                          $-1           $-1               2008/06                 income:gifts                           $-1           $-2 -       Periods with no activity, and summary postings with a zero amount,  are+       Periods  with no activity, and summary postings with a zero amount, are        not shown by default; use the --empty/-E flag to see them:                $ hledger register --monthly income -E@@ -1580,7 +1683,7 @@               2008/11                                                          0           $-2               2008/12                                                          0           $-2 -       Often,  you'll  want  to  see  just one line per interval.  The --depth+       Often, you'll want to see just one  line  per  interval.   The  --depth        option helps with this, causing subaccounts to be aggregated:                $ hledger register --monthly assets --depth 1h@@ -1588,19 +1691,19 @@               2008/06                 assets                                 $-1             0               2008/12                 assets                                 $-1           $-1 -       Note when using report intervals, if you specify start/end dates  these-       will  be  adjusted  outward  if  necessary to contain a whole number of-       intervals.  This ensures that the first and  last  intervals  are  full+       Note  when using report intervals, if you specify start/end dates these+       will be adjusted outward if necessary to  contain  a  whole  number  of+       intervals.   This  ensures  that  the first and last intervals are full        length and comparable to the others in the report.     Custom register output-       register  uses  the  full terminal width by default, except on windows.-       You can override this by setting the COLUMNS environment variable  (not+       register uses the full terminal width by default,  except  on  windows.+       You  can override this by setting the COLUMNS environment variable (not        a bash shell variable) or by using the --width/-w option. -       The  description  and  account columns normally share the space equally-       (about half of (width - 40) each).  You can adjust  this  by  adding  a-       description  width  as  part  of  --width's  argument, comma-separated:+       The description and account columns normally share  the  space  equally+       (about  half  of  (width  - 40) each).  You can adjust this by adding a+       description width  as  part  of  --width's  argument,  comma-separated:        --width W,D .  Here's a diagram:                <--------------------------------- width (W) ---------------------------------->@@ -1616,14 +1719,22 @@               $ hledger reg -w 100,40           # set overall width 100, description width 40               $ hledger reg -w $COLUMNS,40      # use terminal width, and set description width -       The register command also supports the -o/--output-file  and  -O/--out-+       The  register  command also supports the -o/--output-file and -O/--out-        put-format options for controlling output destination and CSV output. +   register-match+       Print the one posting whose transaction description is closest to DESC,+       in  the  style  of  the register command.  Helps ledger-autosync detect+       already-seen transactions when importing.++   rewrite+       Print all transactions, adding custom postings to the matched ones.+    stats        Show some journal statistics.         -o FILE --output-file=FILE-              write  output  to  FILE.   A  file extension matching one of the+              write output to FILE.  A file  extension  matching  one  of  the               above formats selects that format.                $ hledger stats@@ -1638,47 +1749,50 @@               Accounts                 : 8 (depth 3)               Commodities              : 1 ($) -       The stats command displays summary information for the  whole  journal,-       or  a matched part of it.  With a reporting interval, it shows a report+       The  stats  command displays summary information for the whole journal,+       or a matched part of it.  With a reporting interval, it shows a  report        for each report period.         The stats command also supports -o/--output-file for controlling output        destination. +   tags+       List all the tag names in use.+    test        Run built-in unit tests.                $ hledger test               Cases: 74  Tried: 74  Errors: 0  Failures: 0 -       This  command  runs  hledger's built-in unit tests and displays a quick+       This command runs hledger's built-in unit tests and  displays  a  quick        report.  With a regular expression argument, it selects only tests with        matching names.  It's mainly used in development, but it's also nice to        be able to check your hledger executable for smoke at any time.  ADD-ON COMMANDS-       hledger also searches for external add-on commands,  and  will  include+       hledger  also  searches  for external add-on commands, and will include        these in the commands list.  These are programs or scripts in your PATH-       whose name starts with hledger- and ends with a recognised file  exten-+       whose  name starts with hledger- and ends with a recognised file exten-        sion (currently: no extension, bat,com,exe, hs,lhs,pl,py,rb,rkt,sh). -       Add-ons  can  be  invoked like any hledger command, but there are a few+       Add-ons can be invoked like any hledger command, but there  are  a  few        things to be aware of.  Eg if the hledger-web add-on is installed,         o hledger -h web  shows  hledger's  help,  while  hledger web -h  shows          hledger-web's help. -       o Flags  specific  to  the add-on must have a preceding -- to hide them-         from hledger.  So hledger web --serve --port 9000 will  be  rejected;+       o Flags specific to the add-on must have a preceding --  to  hide  them+         from  hledger.   So hledger web --serve --port 9000 will be rejected;          you must use hledger web -- --serve --port 9000. -       o You    can    always    run    add-ons    directly    if   preferred:+       o You   can    always    run    add-ons    directly    if    preferred:          hledger-web --serve --port 9000. -       Add-ons are a relatively easy way to add local features  or  experiment-       with  new  ideas.   They  can  be  written in any language, but haskell-       scripts have a big advantage:  they  can  use  the  same  hledger  (and-       haskell)  library functions that built-in commands do, for command-line+       Add-ons  are  a relatively easy way to add local features or experiment+       with new ideas.  They can be  written  in  any  language,  but  haskell+       scripts  have  a  big  advantage:  they  can  use the same hledger (and+       haskell) library functions that built-in commands do, for  command-line        options, journal parsing, reporting, etc.         Here are some hledger add-ons available:@@ -1696,7 +1810,7 @@        hledger-web provides a simple web interface.     Third party add-ons-       These are maintained separately, and usually updated  shortly  after  a+       These  are  maintained  separately, and usually updated shortly after a        hledger release.     diff@@ -1704,7 +1818,7 @@        journal file and another.     iadd-       hledger-iadd is a curses-style, more interactive  replacement  for  the+       hledger-iadd  is  a  curses-style, more interactive replacement for the        add command.     interest@@ -1712,19 +1826,19 @@        ing to various schemes.     irr-       hledger-irr calculates the internal rate of  return  of  an  investment+       hledger-irr  calculates  the  internal  rate of return of an investment        account.     Experimental add-ons-       These  are  available  in source form in the hledger repo's bin/ direc-+       These are available in source form in the hledger  repo's  bin/  direc-        tory; installing them is pretty easy.  They may be less mature and doc--       umented  than  built-in commands.  Reading and tweaking these is a good+       umented than built-in commands.  Reading and tweaking these is  a  good        way to start making your own!     autosync        hledger-autosync is a symbolic link for easily running ledger-autosync,-       if  installed.   ledger-autosync  does  deduplicating conversion of OFX-       data and some CSV formats, and can also download the data if your  bank+       if installed.  ledger-autosync does  deduplicating  conversion  of  OFX+       data  and some CSV formats, and can also download the data if your bank        offers OFX Direct Connect.     budget@@ -1736,48 +1850,22 @@    check        hledger-check.hs checks more powerful account balance assertions. -   check-dates-       hledger-check-dates.hs checks that journal entries are ordered by date.--   check-dupes-       hledger-check-dupes.hs checks for account names sharing the  same  leaf-       name.--   equity-       hledger-equity.hs  prints  balance-resetting  transactions,  useful for-       bringing account balances across file boundaries.--   prices-       hledger-prices.hs prints all prices from the journal.--   print-unique-       hledger-print-unique.hs prints  transactions  which  do  not  reuse  an-       already-seen description.--   register-match-       hledger-register-match.hs  helps  ledger-autosync  detect  already-seen-       transactions when importing.--   rewrite-       hledger-rewrite.hs Adds one or more custom postings to matched transac--       tions.- ENVIRONMENT-       COLUMNS  The  screen  width used by the register command.  Default: the+       COLUMNS The screen width used by the register  command.   Default:  the        full terminal width.         LEDGER_FILE The journal file path when not specified with -f.  Default:-       ~/.hledger.journal  (on  windows,  perhaps C:/Users/USER/.hledger.jour-+       ~/.hledger.journal (on  windows,  perhaps  C:/Users/USER/.hledger.jour-        nal).  FILES-       Reads data from one or more files in hledger journal, timeclock,  time--       dot,   or   CSV   format   specified   with  -f,  or  $LEDGER_FILE,  or-       $HOME/.hledger.journal          (on          windows,           perhaps+       Reads  data from one or more files in hledger journal, timeclock, time-+       dot,  or  CSV  format  specified   with   -f,   or   $LEDGER_FILE,   or+       $HOME/.hledger.journal           (on          windows,          perhaps        C:/Users/USER/.hledger.journal).  BUGS-       The  need  to  precede  addon command options with -- when invoked from+       The need to precede addon command options with  --  when  invoked  from        hledger is awkward.         When input data contains non-ascii characters, a suitable system locale@@ -1790,33 +1878,33 @@        In a Cygwin/MSYS/Mintty window, the tab key is not supported in hledger        add. -       Not all of Ledger's journal file syntax is supported.  See file  format+       Not  all of Ledger's journal file syntax is supported.  See file format        differences. -       On  large  data  files,  hledger  is  slower  and uses more memory than+       On large data files, hledger  is  slower  and  uses  more  memory  than        Ledger.  TROUBLESHOOTING-       Here are some issues you might encounter  when  you  run  hledger  (and-       remember  you can also seek help from the IRC channel, mail list or bug+       Here  are  some  issues  you  might encounter when you run hledger (and+       remember you can also seek help from the IRC channel, mail list or  bug        tracker):         Successfully installed, but "No command 'hledger' found"        stack and cabal install binaries into a special directory, which should-       be  added  to your PATH environment variable.  Eg on unix-like systems,+       be added to your PATH environment variable.  Eg on  unix-like  systems,        that is ~/.local/bin and ~/.cabal/bin respectively.         I set a custom LEDGER_FILE, but hledger is still using the default file-       LEDGER_FILE  should  be  a  real environment variable, not just a shell-       variable.  The command env | grep LEDGER_FILE should show it.  You  may+       LEDGER_FILE should be a real environment variable,  not  just  a  shell+       variable.   The command env | grep LEDGER_FILE should show it.  You may        need to use export.  Here's an explanation. -       "Illegal  byte  sequence"  or  "Invalid or incomplete multibyte or wide+       "Illegal byte sequence" or "Invalid or  incomplete  multibyte  or  wide        character" errors        In order to handle non-ascii letters and symbols (like ), hledger needs        an appropriate locale.  This is usually configured system-wide; you can        also configure it temporarily.  The locale may need to be one that sup--       ports  UTF-8,  if you built hledger with GHC < 7.2 (or possibly always,+       ports UTF-8, if you built hledger with GHC < 7.2 (or  possibly  always,        I'm not sure yet).         Here's  an  example  of  setting  the  locale  temporarily,  on  ubuntu@@ -1835,7 +1923,7 @@               $ echo "export LANG=en_US.UTF-8" >>~/.bash_profile               $ bash --login -       If  we  preferred  to  use eg fr_FR.utf8, we might have to install that+       If we preferred to use eg fr_FR.utf8, we might  have  to  install  that        first:                $ apt-get install language-pack-fr@@ -1856,7 +1944,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)  @@ -1870,7 +1958,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) @@ -1878,4 +1966,4 @@   -hledger 1.3.1                     August 2017                       hledger(1)+hledger 1.4                     September 2017                      hledger(1)
doc/other/hledger-api.1 view
@@ -1,5 +1,5 @@ -.TH "hledger\-api" "1" "August 2017" "hledger\-api 1.3.1" "hledger User Manuals"+.TH "hledger\-api" "1" "September 2017" "hledger\-api 1.4" "hledger User Manuals"   @@ -79,23 +79,8 @@ .RS .RE .TP-.B \f[C]\-h\f[]+.B \f[C]\-h\ \-\-help\f[] show usage-.RS-.RE-.TP-.B \f[C]\-\-help\f[]-show manual as plain text-.RS-.RE-.TP-.B \f[C]\-\-man\f[]-show manual with man-.RS-.RE-.TP-.B \f[C]\-\-info\f[]-show manual with info .RS .RE .SH ENVIRONMENT
doc/other/hledger-api.1.info view
@@ -3,8 +3,8 @@  File: hledger-api.1.info,  Node: Top,  Next: OPTIONS,  Up: (dir) -hledger-api(1) hledger-api 1.3.1-********************************+hledger-api(1) hledger-api 1.4+******************************  hledger-api is a simple web API server, intended to support client-side web apps operating on hledger data.  It comes with a series of simple@@ -57,23 +57,14 @@ '--version'       show version-'-h'+'-h --help'       show usage-'--help' -     show manual as plain text-'--man'--     show manual with man-'--info'--     show manual with info-  Tag Table: Node: Top74-Node: OPTIONS1224-Ref: #options1311+Node: OPTIONS1220+Ref: #options1307  End Tag Table
doc/other/hledger-api.1.txt view
@@ -59,13 +59,8 @@        --version               show version -       -h     show usage--       --help show manual as plain text--       --man  show manual with man--       --info show manual with info+       -h --help+              show usage  ENVIRONMENT        LEDGER_FILE The journal file path when not specified with -f.  Default:@@ -107,4 +102,4 @@   -hledger-api 1.3.1                 August 2017                   hledger-api(1)+hledger-api 1.4                 September 2017                  hledger-api(1)
doc/other/hledger-ui.1 view
@@ -1,5 +1,5 @@ -.TH "hledger\-ui" "1" "August 2017" "hledger\-ui 1.3.1" "hledger User Manuals"+.TH "hledger\-ui" "1" "September 2017" "hledger\-ui 1.4" "hledger User Manuals"   @@ -88,8 +88,8 @@ .RS .RE .TP-.B \f[C]\-\-pivot\ TAGNAME\f[]-use some other field/tag for account names+.B \f[C]\-\-pivot\ FIELDNAME\f[]+use some other field or tag for the account name .RS .RE .TP@@ -142,7 +142,7 @@ .RE .TP .B \f[C]\-\-date2\f[]-show, and match with \-b/\-e/\-p/date:, secondary dates instead+match the secondary date instead (see command help for other effects) .RS .RE .TP@@ -166,8 +166,8 @@ .RS .RE .TP-.B \f[C]\-\-depth=N\f[]-hide accounts/postings deeper than N+.B \f[C]\-NUM\ \-\-depth=NUM\f[]+hide/aggregate accounts or postings more than NUM levels deep .RS .RE .TP@@ -188,29 +188,18 @@ .RS .RE .PP+When a reporting option appears more than once in the command line, the+last one takes precedence.+.PP+Some reporting options can also be written as query arguments.+.PP hledger help options: .TP-.B \f[C]\-h\f[]+.B \f[C]\-h\ \-\-help\f[] show general usage (or after COMMAND, command usage) .RS .RE .TP-.B \f[C]\-\-help\f[]-show this program\[aq]s manual as plain text (or after an add\-on-COMMAND, the add\-on\[aq]s manual)-.RS-.RE-.TP-.B \f[C]\-\-man\f[]-show this program\[aq]s manual with man-.RS-.RE-.TP-.B \f[C]\-\-info\f[]-show this program\[aq]s manual with info-.RS-.RE-.TP .B \f[C]\-\-version\f[] show version .RS@@ -220,6 +209,10 @@ show debug output (levels 1\-9, default: 1) .RS .RE+.PP+A \@FILE argument will be expanded to the contents of FILE, which should+contain one command line option/argument per line.+(To prevent this, insert a \f[C]\-\-\f[] argument before.) .SH KEYS .PP \f[C]?\f[] shows a help dialog listing all keys.
doc/other/hledger-ui.1.info view
@@ -3,8 +3,8 @@  File: hledger-ui.1.info,  Node: Top,  Next: OPTIONS,  Up: (dir) -hledger-ui(1) hledger-ui 1.3.1-******************************+hledger-ui(1) hledger-ui 1.4+****************************  hledger-ui is hledger's curses-style interface, providing an efficient full-window text UI for viewing accounts and transactions, and some@@ -67,9 +67,9 @@ '--anon'       anonymize accounts and payees-'--pivot TAGNAME'+'--pivot FIELDNAME' -     use some other field/tag for account names+     use some other field or tag for the account name '-I --ignore-assertions'       ignore any failing balance assertions@@ -103,7 +103,8 @@      (overrides the flags above) '--date2' -     show, and match with -b/-e/-p/date:, secondary dates instead+     match the secondary date instead (see command help for other+     effects) '-U --unmarked'       include only unmarked postings/txns (can combine with -P or -C)@@ -116,9 +117,9 @@ '-R --real'       include only non-virtual postings-'--depth=N'+'-NUM --depth=NUM' -     hide accounts/postings deeper than N+     hide/aggregate accounts or postings more than NUM levels deep '-E --empty'       show items with zero amount, normally hidden@@ -131,21 +132,16 @@      convert amounts to their market value on the report end date (using      the most recent applicable market price, if any) -   hledger help options:--'-h'+   When a reporting option appears more than once in the command line,+the last one takes precedence. -     show general usage (or after COMMAND, command usage)-'--help'+   Some reporting options can also be written as query arguments. -     show this program's manual as plain text (or after an add-on-     COMMAND, the add-on's manual)-'--man'+   hledger help options: -     show this program's manual with man-'--info'+'-h --help' -     show this program's manual with info+     show general usage (or after COMMAND, command usage) '--version'       show version@@ -153,6 +149,10 @@       show debug output (levels 1-9, default: 1) +   A @FILE argument will be expanded to the contents of FILE, which+should contain one command line option/argument per line.  (To prevent+this, insert a '--' argument before.)+  File: hledger-ui.1.info,  Node: KEYS,  Next: SCREENS,  Prev: OPTIONS,  Up: Top @@ -365,19 +365,19 @@  Tag Table: Node: Top73-Node: OPTIONS829-Ref: #options928-Node: KEYS3669-Ref: #keys3766-Node: SCREENS6562-Ref: #screens6649-Node: Accounts screen6739-Ref: #accounts-screen6869-Node: Register screen9099-Ref: #register-screen9256-Node: Transaction screen11330-Ref: #transaction-screen11490-Node: Error screen12360-Ref: #error-screen12484+Node: OPTIONS825+Ref: #options924+Node: KEYS3861+Ref: #keys3958+Node: SCREENS6754+Ref: #screens6841+Node: Accounts screen6931+Ref: #accounts-screen7061+Node: Register screen9291+Ref: #register-screen9448+Node: Transaction screen11522+Ref: #transaction-screen11682+Node: Error screen12552+Ref: #error-screen12676  End Tag Table
doc/other/hledger-ui.1.txt view
@@ -65,8 +65,8 @@         --anon anonymize accounts and payees -       --pivot TAGNAME-              use some other field/tag for account names+       --pivot FIELDNAME+              use some other field or tag for the account name         -I --ignore-assertions               ignore any failing balance assertions@@ -99,7 +99,8 @@               (overrides the flags above)         --date2-              show, and match with -b/-e/-p/date:, secondary dates instead+              match the secondary date instead (see  command  help  for  other+              effects)         -U --unmarked               include only unmarked postings/txns (can combine with -P or -C)@@ -113,30 +114,29 @@        -R --real               include only non-virtual postings -       --depth=N-              hide accounts/postings deeper than N+       -NUM --depth=NUM+              hide/aggregate accounts or postings more than NUM levels deep         -E --empty               show items with zero amount, normally hidden         -B --cost-              convert amounts to their cost at  transaction  time  (using  the+              convert  amounts  to  their  cost at transaction time (using the               transaction price, if any)         -V --value-              convert  amounts  to  their  market value on the report end date+              convert amounts to their market value on  the  report  end  date               (using the most recent applicable market price, if any) -       hledger help options:--       -h     show general usage (or after COMMAND, command usage)+       When a reporting option appears more than once in the command line, the+       last one takes precedence. -       --help show this program's manual as plain text  (or  after  an  add-on-              COMMAND, the add-on's manual)+       Some reporting options can also be written as query arguments. -       --man  show this program's manual with man+       hledger help options: -       --info show this program's manual with info+       -h --help+              show general usage (or after COMMAND, command usage)         --version               show version@@ -144,57 +144,61 @@        --debug[=N]               show debug output (levels 1-9, default: 1) +       A @FILE argument will be expanded to the contents of FILE, which should+       contain  one  command line option/argument per line.  (To prevent this,+       insert a -- argument before.)+ KEYS-       ?  shows a help dialog listing all keys.  (Some of these also appear in+       ? shows a help dialog listing all keys.  (Some of these also appear  in        the quick help at the bottom of each screen.) Press ? again (or ESCAPE,        or LEFT) to close it.  The following keys work on most screens:         The cursor keys navigate: right (or enter) goes deeper, left returns to-       the previous screen,  up/down/page up/page down/home/end  move  up  and-       down    through    lists.     Vi-style    (h/j/k/l)   and   Emacs-style+       the  previous  screen,  up/down/page up/page down/home/end  move up and+       down   through   lists.     Vi-style    (h/j/k/l)    and    Emacs-style        (CTRL-p/CTRL-n/CTRL-f/CTRL-b) movement keys are also supported.  A tip:-       movement  speed is limited by your keyboard repeat rate, to move faster-       you may want to adjust it.  (If you're on a mac, the Karabiner  app  is+       movement speed is limited by your keyboard repeat rate, to move  faster+       you  may  want to adjust it.  (If you're on a mac, the Karabiner app is        one way to do that.) -       With  shift pressed, the cursor keys adjust the report period, limiting-       the  transactions  to  be  shown   (by   default,   all   are   shown).-       shift-down/up  steps  downward and upward through these standard report+       With shift pressed, the cursor keys adjust the report period,  limiting+       the   transactions   to   be   shown   (by  default,  all  are  shown).+       shift-down/up steps downward and upward through these  standard  report        period   durations:   year,   quarter,   month,   week,   day.    Then,-       shift-left/right  moves to the previous/next period.  t sets the report-       period to today.  With the --watch option,  when  viewing  a  "current"-       period  (the  current  day,  week, month, quarter, or year), the period-       will move automatically to track the current date.  To set a  non-stan-+       shift-left/right moves to the previous/next period.  t sets the  report+       period  to  today.   With  the --watch option, when viewing a "current"+       period (the current day, week, month, quarter,  or  year),  the  period+       will  move automatically to track the current date.  To set a non-stan-        dard period, you can use / and a date: query. -       /  lets  you  set a general filter query limiting the data shown, using-       the same query terms as in hledger and hledger-web.  While editing  the-       query,  you  can  use CTRL-a/e/d/k, BS, cursor keys; press ENTER to set+       / lets you set a general filter query limiting the  data  shown,  using+       the  same query terms as in hledger and hledger-web.  While editing the+       query, you can use CTRL-a/e/d/k, BS, cursor keys; press  ENTER  to  set        it, or ESCAPEto cancel.  There are also keys for quickly adjusting some-       common  filters  like account depth and transaction status (see below).+       common filters like account depth and transaction status  (see  below).        BACKSPACE or DELETE removes all filters, showing all transactions. -       ESCAPE removes all filters and jumps back to the top  screen.   Or,  it+       ESCAPE  removes  all  filters and jumps back to the top screen.  Or, it        cancels a minibuffer edit or help dialog in progress.         CTRL-l redraws the screen and centers the selection if possible (selec--       tions near the top won't be centered, since we don't scroll  above  the+       tions  near  the top won't be centered, since we don't scroll above the        top). -       g  reloads from the data file(s) and updates the current screen and any-       previous screens.  (With large files, this  could  cause  a  noticeable+       g reloads from the data file(s) and updates the current screen and  any+       previous  screens.   (With  large  files, this could cause a noticeable        pause.) -       I  toggles  balance  assertion  checking.  Disabling balance assertions+       I toggles balance assertion  checking.   Disabling  balance  assertions        temporarily can be useful for troubleshooting. -       a runs command-line hledger's add  command,  and  reloads  the  updated+       a  runs  command-line  hledger's  add  command, and reloads the updated        file.  This allows some basic data entry. -       E   runs   $HLEDGER_UI_EDITOR,   or   $EDITOR,   or  a  default  (emac-+       E  runs  $HLEDGER_UI_EDITOR,  or   $EDITOR,   or   a   default   (emac-        sclient -a "" -nw) on the journal file.  With some editors (emacs, vi),-       the  cursor  will be positioned at the current transaction when invoked-       from the register and transaction screens, and at  the  error  location+       the cursor will be positioned at the current transaction  when  invoked+       from  the  register  and transaction screens, and at the error location        (if possible) when invoked from the error screen.         q quits the application.@@ -203,44 +207,44 @@  SCREENS    Accounts screen-       This  is  normally  the  first screen displayed.  It lists accounts and-       their balances, like hledger's balance command.  By default,  it  shows-       all  accounts  and their latest ending balances (including the balances-       of subaccounts).  if you specify a query on the command line, it  shows+       This is normally the first screen displayed.   It  lists  accounts  and+       their  balances,  like hledger's balance command.  By default, it shows+       all accounts and their latest ending balances (including  the  balances+       of  subaccounts).  if you specify a query on the command line, it shows        just the matched accounts and the balances from matched transactions. -       Account  names are normally indented to show the hierarchy (tree mode).+       Account names are normally indented to show the hierarchy (tree  mode).        To see less detail, set a depth limit by pressing a number key, 1 to 9.        0 shows even less detail, collapsing all accounts to a single total.  --       and + (or =) decrease and increase the  depth  limit.   To  remove  the-       depth  limit,  set  it  higher than the maximum account depth, or press+       and  +  (or  =)  decrease  and increase the depth limit.  To remove the+       depth limit, set it higher than the maximum  account  depth,  or  press        ESCAPE. -       F toggles flat mode, in which accounts are shown as a flat  list,  with-       their  full names.  In this mode, account balances exclude subaccounts,-       except for accounts at the depth limit (as with hledger's balance  com-+       F  toggles  flat mode, in which accounts are shown as a flat list, with+       their full names.  In this mode, account balances exclude  subaccounts,+       except  for accounts at the depth limit (as with hledger's balance com-        mand).         H toggles between showing historical balances or period balances.  His--       torical balances (the default) are ending balances at the  end  of  the-       report  period,  taking  into account all transactions before that date-       (filtered by the filter query if any),  including  transactions  before-       the  start  of  the report period.  In other words, historical balances-       are what you would see on a bank statement  for  that  account  (unless-       disturbed  by  a  filter  query).   Period balances ignore transactions+       torical  balances  (the  default) are ending balances at the end of the+       report period, taking into account all transactions  before  that  date+       (filtered  by  the  filter query if any), including transactions before+       the start of the report period.  In other  words,  historical  balances+       are  what  you  would  see on a bank statement for that account (unless+       disturbed by a filter  query).   Period  balances  ignore  transactions        before the report start date, so they show the change in balance during        the report period.  They are more useful eg when viewing a time log.         U toggles filtering by unmarked status, including or excluding unmarked        postings in the balances.  Similarly, P toggles pending postings, and C-       toggles  cleared postings.  (By default, balances include all postings;-       if you activate one or two status  filters,  only  those  postings  are+       toggles cleared postings.  (By default, balances include all  postings;+       if  you  activate  one  or  two status filters, only those postings are        included; and if you activate all three, the filter is removed.)         R toggles real mode, in which virtual postings are ignored. -       Z  toggles  nonzero  mode, in which only accounts with nonzero balances-       are shown (hledger-ui shows zero items by default, unlike  command-line+       Z toggles nonzero mode, in which only accounts  with  nonzero  balances+       are  shown (hledger-ui shows zero items by default, unlike command-line        hledger).         Press right or enter to view an account's transactions register.@@ -249,65 +253,65 @@        This screen shows the transactions affecting a particular account, like        a check register.  Each line represents one transaction and shows: -       o the other account(s) involved, in abbreviated form.   (If  there  are-         both  real  and virtual postings, it shows only the accounts affected+       o the  other  account(s)  involved, in abbreviated form.  (If there are+         both real and virtual postings, it shows only the  accounts  affected          by real postings.) -       o the overall change to the current account's balance; positive for  an+       o the  overall change to the current account's balance; positive for an          inflow to this account, negative for an outflow.         o the running historical total or period total for the current account,-         after the transaction.  This can be toggled with H.  Similar  to  the-         accounts  screen,  the  historical  total is affected by transactions-         (filtered by the filter query) before the report  start  date,  while+         after  the  transaction.  This can be toggled with H.  Similar to the+         accounts screen, the historical total  is  affected  by  transactions+         (filtered  by  the  filter query) before the report start date, while          the period total is not.  If the historical total is not disturbed by-         a filter query, it will be the running historical balance  you  would+         a  filter  query, it will be the running historical balance you would          see on a bank register for the current account. -       If  the  accounts  screen  was  in  tree mode, the register screen will+       If the accounts screen was in  tree  mode,  the  register  screen  will        include transactions from both the current account and its subaccounts.-       If  the  accounts  screen  was  in  flat  mode, and a non-depth-clipped-       account was selected, the register  screen  will  exclude  transactions+       If the accounts screen  was  in  flat  mode,  and  a  non-depth-clipped+       account  was  selected,  the  register screen will exclude transactions        from subaccounts.  In other words, the register always shows the trans--       actions responsible for  the  period  balance  shown  on  the  accounts+       actions  responsible  for  the  period  balance  shown  on the accounts        screen.  As on the accounts screen, this can be toggled with F. -       U  toggles  filtering  by  unmarked  status, showing or hiding unmarked+       U toggles filtering by unmarked  status,  showing  or  hiding  unmarked        transactions.  Similarly, P toggles pending transactions, and C toggles-       cleared  transactions.  (By default, transactions with all statuses are-       shown; if you activate one or two status filters, only  those  transac--       tions  are  shown;  and  if  you  activate  all  three,  the  filter is+       cleared transactions.  (By default, transactions with all statuses  are+       shown;  if  you activate one or two status filters, only those transac-+       tions are  shown;  and  if  you  activate  all  three,  the  filter  is        removed.)q         R toggles real mode, in which virtual postings are ignored. -       Z toggles nonzero mode, in which only transactions  posting  a  nonzero-       change  are  shown (hledger-ui shows zero items by default, unlike com-+       Z  toggles  nonzero  mode, in which only transactions posting a nonzero+       change are shown (hledger-ui shows zero items by default,  unlike  com-        mand-line hledger).         Press right (or enter) to view the selected transaction in detail.     Transaction screen-       This screen shows a single transaction, as  a  general  journal  entry,-       similar  to  hledger's  print command and journal format (hledger_jour-+       This  screen  shows  a  single transaction, as a general journal entry,+       similar to hledger's print command and  journal  format  (hledger_jour-        nal(5)). -       The transaction's date(s)  and  any  cleared  flag,  transaction  code,-       description,  comments,  along  with  all  of  its account postings are-       shown.  Simple transactions have two postings, but there  can  be  more+       The  transaction's  date(s)  and  any  cleared  flag, transaction code,+       description, comments, along with  all  of  its  account  postings  are+       shown.   Simple  transactions  have two postings, but there can be more        (or in certain cases, fewer). -       up  and  down will step through all transactions listed in the previous-       account register screen.  In the title bar, the numbers in  parentheses-       show  your  position  within  that  account  register.   They will vary+       up and down will step through all transactions listed in  the  previous+       account  register screen.  In the title bar, the numbers in parentheses+       show your position  within  that  account  register.   They  will  vary        depending on which account register you came from (remember most trans-        actions appear in multiple account registers).  The #N number preceding        them is the transaction's position within the complete unfiltered jour-        nal, which is a more stable id (at least until the next reload).     Error screen-       This  screen  will appear if there is a problem, such as a parse error,-       when you press g to reload.  Once you have fixed the problem,  press  g+       This screen will appear if there is a problem, such as a  parse  error,+       when  you  press g to reload.  Once you have fixed the problem, press g        again to reload and resume normal operation.  (Or, you can press escape        to cancel the reload attempt.) @@ -315,17 +319,17 @@        COLUMNS The screen width to use.  Default: the full terminal width.         LEDGER_FILE The journal file path when not specified with -f.  Default:-       ~/.hledger.journal  (on  windows,  perhaps C:/Users/USER/.hledger.jour-+       ~/.hledger.journal (on  windows,  perhaps  C:/Users/USER/.hledger.jour-        nal).  FILES-       Reads data from one or more files in hledger journal, timeclock,  time--       dot,   or   CSV   format   specified   with  -f,  or  $LEDGER_FILE,  or-       $HOME/.hledger.journal          (on          windows,           perhaps+       Reads  data from one or more files in hledger journal, timeclock, time-+       dot,  or  CSV  format  specified   with   -f,   or   $LEDGER_FILE,   or+       $HOME/.hledger.journal           (on          windows,          perhaps        C:/Users/USER/.hledger.journal).  BUGS-       The  need  to precede options with -- when invoked from hledger is awk-+       The need to precede options with -- when invoked from hledger  is  awk-        ward.         -f- doesn't work (hledger-ui can't read from stdin).@@ -333,13 +337,13 @@        -V affects only the accounts screen.         When you press g, the current and all previous screens are regenerated,-       which  may cause a noticeable pause with large files.  Also there is no+       which may cause a noticeable pause with large files.  Also there is  no        visual indication that this is in progress. -       --watch is not yet fully robust.  It works well for normal  usage,  but-       many  file  changes  in  a  short time (eg saving the file thousands of-       times with an editor macro) can cause problems at least on OSX.   Symp--       toms  include:  unresponsive UI, periodic resetting of the cursor posi-+       --watch  is  not yet fully robust.  It works well for normal usage, but+       many file changes in a short time (eg  saving  the  file  thousands  of+       times  with an editor macro) can cause problems at least on OSX.  Symp-+       toms include: unresponsive UI, periodic resetting of the  cursor  posi-        tion, momentary display of parse errors, high CPU usage eventually sub-        siding, and possibly a small but persistent build-up of CPU usage until        the program is restarted.@@ -347,7 +351,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)  @@ -361,7 +365,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) @@ -369,4 +373,4 @@   -hledger-ui 1.3.1                  August 2017                    hledger-ui(1)+hledger-ui 1.4                  September 2017                   hledger-ui(1)
doc/other/hledger-web.1 view
@@ -1,5 +1,5 @@ -.TH "hledger\-web" "1" "August 2017" "hledger\-web 1.3.1" "hledger User Manuals"+.TH "hledger\-web" "1" "September 2017" "hledger\-web 1.4" "hledger User Manuals"   @@ -144,8 +144,8 @@ .RS .RE .TP-.B \f[C]\-\-pivot\ TAGNAME\f[]-use some other field/tag for account names+.B \f[C]\-\-pivot\ FIELDNAME\f[]+use some other field or tag for the account name .RS .RE .TP@@ -198,7 +198,7 @@ .RE .TP .B \f[C]\-\-date2\f[]-show, and match with \-b/\-e/\-p/date:, secondary dates instead+match the secondary date instead (see command help for other effects) .RS .RE .TP@@ -222,8 +222,8 @@ .RS .RE .TP-.B \f[C]\-\-depth=N\f[]-hide accounts/postings deeper than N+.B \f[C]\-NUM\ \-\-depth=NUM\f[]+hide/aggregate accounts or postings more than NUM levels deep .RS .RE .TP@@ -244,29 +244,18 @@ .RS .RE .PP+When a reporting option appears more than once in the command line, the+last one takes precedence.+.PP+Some reporting options can also be written as query arguments.+.PP hledger help options: .TP-.B \f[C]\-h\f[]+.B \f[C]\-h\ \-\-help\f[] show general usage (or after COMMAND, command usage) .RS .RE .TP-.B \f[C]\-\-help\f[]-show this program\[aq]s manual as plain text (or after an add\-on-COMMAND, the add\-on\[aq]s manual)-.RS-.RE-.TP-.B \f[C]\-\-man\f[]-show this program\[aq]s manual with man-.RS-.RE-.TP-.B \f[C]\-\-info\f[]-show this program\[aq]s manual with info-.RS-.RE-.TP .B \f[C]\-\-version\f[] show version .RS@@ -276,6 +265,10 @@ show debug output (levels 1\-9, default: 1) .RS .RE+.PP+A \@FILE argument will be expanded to the contents of FILE, which should+contain one command line option/argument per line.+(To prevent this, insert a \f[C]\-\-\f[] argument before.) .SH ENVIRONMENT .PP \f[B]LEDGER_FILE\f[] The journal file path when not specified with
doc/other/hledger-web.1.info view
@@ -3,8 +3,8 @@  File: hledger-web.1.info,  Node: Top,  Next: OPTIONS,  Up: (dir) -hledger-web(1) hledger-web 1.3.1-********************************+hledger-web(1) hledger-web 1.4+******************************  hledger-web is hledger's web interface.  It starts a simple web application for browsing and adding transactions, and optionally opens@@ -112,9 +112,9 @@ '--anon'       anonymize accounts and payees-'--pivot TAGNAME'+'--pivot FIELDNAME' -     use some other field/tag for account names+     use some other field or tag for the account name '-I --ignore-assertions'       ignore any failing balance assertions@@ -148,7 +148,8 @@      (overrides the flags above) '--date2' -     show, and match with -b/-e/-p/date:, secondary dates instead+     match the secondary date instead (see command help for other+     effects) '-U --unmarked'       include only unmarked postings/txns (can combine with -P or -C)@@ -161,9 +162,9 @@ '-R --real'       include only non-virtual postings-'--depth=N'+'-NUM --depth=NUM' -     hide accounts/postings deeper than N+     hide/aggregate accounts or postings more than NUM levels deep '-E --empty'       show items with zero amount, normally hidden@@ -176,21 +177,16 @@      convert amounts to their market value on the report end date (using      the most recent applicable market price, if any) -   hledger help options:--'-h'+   When a reporting option appears more than once in the command line,+the last one takes precedence. -     show general usage (or after COMMAND, command usage)-'--help'+   Some reporting options can also be written as query arguments. -     show this program's manual as plain text (or after an add-on-     COMMAND, the add-on's manual)-'--man'+   hledger help options: -     show this program's manual with man-'--info'+'-h --help' -     show this program's manual with info+     show general usage (or after COMMAND, command usage) '--version'       show version@@ -198,10 +194,14 @@       show debug output (levels 1-9, default: 1) +   A @FILE argument will be expanded to the contents of FILE, which+should contain one command line option/argument per line.  (To prevent+this, insert a '--' argument before.)+  Tag Table: Node: Top74-Node: OPTIONS3160-Ref: #options3247+Node: OPTIONS3156+Ref: #options3243  End Tag Table
doc/other/hledger-web.1.txt view
@@ -110,8 +110,8 @@         --anon anonymize accounts and payees -       --pivot TAGNAME-              use some other field/tag for account names+       --pivot FIELDNAME+              use some other field or tag for the account name         -I --ignore-assertions               ignore any failing balance assertions@@ -144,7 +144,8 @@               (overrides the flags above)         --date2-              show, and match with -b/-e/-p/date:, secondary dates instead+              match  the  secondary  date  instead (see command help for other+              effects)         -U --unmarked               include only unmarked postings/txns (can combine with -P or -C)@@ -158,30 +159,29 @@        -R --real               include only non-virtual postings -       --depth=N-              hide accounts/postings deeper than N+       -NUM --depth=NUM+              hide/aggregate accounts or postings more than NUM levels deep         -E --empty               show items with zero amount, normally hidden         -B --cost-              convert  amounts  to  their  cost at transaction time (using the+              convert amounts to their cost at  transaction  time  (using  the               transaction price, if any)         -V --value-              convert amounts to their market value on  the  report  end  date+              convert  amounts  to  their  market value on the report end date               (using the most recent applicable market price, if any) -       hledger help options:--       -h     show general usage (or after COMMAND, command usage)+       When a reporting option appears more than once in the command line, the+       last one takes precedence. -       --help show  this  program's  manual  as plain text (or after an add-on-              COMMAND, the add-on's manual)+       Some reporting options can also be written as query arguments. -       --man  show this program's manual with man+       hledger help options: -       --info show this program's manual with info+       -h --help+              show general usage (or after COMMAND, command usage)         --version               show version@@ -189,19 +189,23 @@        --debug[=N]               show debug output (levels 1-9, default: 1) +       A @FILE argument will be expanded to the contents of FILE, which should+       contain one command line option/argument per line.  (To  prevent  this,+       insert a -- argument before.)+ ENVIRONMENT        LEDGER_FILE The journal file path when not specified with -f.  Default:-       ~/.hledger.journal  (on  windows,  perhaps C:/Users/USER/.hledger.jour-+       ~/.hledger.journal (on  windows,  perhaps  C:/Users/USER/.hledger.jour-        nal).  FILES-       Reads data from one or more files in hledger journal, timeclock,  time--       dot,   or   CSV   format   specified   with  -f,  or  $LEDGER_FILE,  or-       $HOME/.hledger.journal          (on          windows,           perhaps+       Reads  data from one or more files in hledger journal, timeclock, time-+       dot,  or  CSV  format  specified   with   -f,   or   $LEDGER_FILE,   or+       $HOME/.hledger.journal           (on          windows,          perhaps        C:/Users/USER/.hledger.journal).  BUGS-       The  need  to precede options with -- when invoked from hledger is awk-+       The need to precede options with -- when invoked from hledger  is  awk-        ward.         -f- doesn't work (hledger-web can't read from stdin).@@ -215,7 +219,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)  @@ -229,7 +233,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) @@ -237,4 +241,4 @@   -hledger-web 1.3.1                 August 2017                   hledger-web(1)+hledger-web 1.4                 September 2017                  hledger-web(1)
doc/other/hledger_csv.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_csv" "5" "August 2017" "hledger 1.3.1" "hledger User Manuals"+.TH "hledger_csv" "5" "September 2017" "hledger 1.4" "hledger User Manuals"   @@ -23,7 +23,7 @@ To learn about \f[I]exporting\f[] CSV, see CSV output. .SH CSV RULES .PP-The following six kinds of rule can appear in the rules file, in any+The following seven kinds of rule can appear in the rules file, in any order. Blank lines and lines beginning with \f[C]#\f[] or \f[C];\f[] are ignored.@@ -195,32 +195,65 @@ include\ common.rules \f[] .fi+.SS newest\-first+.PP+\f[C]newest\-first\f[]+.PP+Consider adding this rule if all of the following are true: you might be+processing just one day of data, your CSV records are in reverse+chronological order (newest first), and you care about preserving the+order of same\-day transactions.+It usually isn\[aq]t needed, because hledger autodetects the CSV order,+but when all CSV records have the same date it will assume they are+oldest first. .SH CSV TIPS+.SS CSV ordering .PP-Each generated journal entry will have two postings, to-\f[C]account1\f[] and \f[C]account2\f[] respectively.-Currently it\[aq]s not possible to generate entries with more than two+The generated journal entries will be sorted by date.+The order of same\-day entries will be preserved (except in the special+case where you might need \f[C]newest\-first\f[], see above).+.SS CSV accounts+.PP+Each journal entry will have two postings, to \f[C]account1\f[] and+\f[C]account2\f[] respectively.+It\[aq]s not yet possible to generate entries with more than two postings.+It\[aq]s conventional and recommended to use \f[C]account1\f[] for the+account whose CSV we are reading.+.SS CSV amounts .PP+The \f[C]amount\f[] field sets the amount of the \f[C]account1\f[]+posting.+.PP If the CSV has debit/credit amounts in separate fields, assign to the-\f[C]amount\-in\f[] and \f[C]amount\-out\f[] pseudo fields instead of-\f[C]amount\f[].+\f[C]amount\-in\f[] and \f[C]amount\-out\f[] pseudo fields instead.+(Whichever one has a value will be used, with appropriate sign.+If both contain a value, it may not work so well.) .PP-If the CSV has the currency in a separate field, assign that to the-\f[C]currency\f[] pseudo field which will be automatically prepended to-the amount.-(Or you can do the same thing with a field assignment.)+If an amount value is parenthesised, it will be de\-parenthesised and+sign\-flipped. .PP-If the CSV includes a running balance, you can assign that to the-\f[C]balance\f[] pseudo field to generate a balance assertion on-\f[C]account1\f[] whenever the balance field is non\-empty.-(Eg to double\-check your bank\[aq]s balance calculation.)+If an amount value begins with a double minus sign, those will cancel+out and be removed. .PP-If an amount value is parenthesised, it will be de\-parenthesised and-sign\-flipped automatically.+If the CSV has the currency symbol in a separate field, assign that to+the \f[C]currency\f[] pseudo field to have it prepended to the amount.+Or, you can use a field assignment to \f[C]amount\f[] that interpolates+both CSV fields (giving more control, eg to put the currency symbol on+the right).+.SS CSV balance assertions .PP-The generated journal entries will be sorted by date.-The original order of same\-day entries will be preserved, usually.+If the CSV includes a running balance, you can assign that to the+\f[C]balance\f[] pseudo field; whenever the running balance value is+non\-empty, it will be asserted as the balance after the+\f[C]account1\f[] posting.+.SS Reading multiple CSV files+.PP+You can read multiple CSV files at once using multiple \f[C]\-f\f[]+arguments on the command line, and hledger will look for a+correspondingly\-named rules file for each.+Note if you use the \f[C]\-\-rules\-file\f[] option, this one rules file+will be used for all the CSV files being read.   .SH "REPORTING BUGS"
doc/other/hledger_csv.5.info view
@@ -3,8 +3,8 @@  File: hledger_csv.5.info,  Node: Top,  Next: CSV RULES,  Up: (dir) -hledger_csv(5) hledger 1.3.1-****************************+hledger_csv(5) hledger 1.4+**************************  hledger can read CSV files, converting each CSV record into a journal entry (transaction), if you provide some conversion hints in a "rules@@ -27,7 +27,7 @@ 1 CSV RULES *********** -The following six kinds of rule can appear in the rules file, in any+The following seven kinds of rule can appear in the rules file, in any order.  Blank lines and lines beginning with '#' or ';' are ignored. * Menu: @@ -37,6 +37,7 @@ * field assignment:: * conditional block:: * include::+* newest-first::   File: hledger_csv.5.info,  Node: skip,  Next: date-format,  Up: CSV RULES@@ -156,7 +157,7 @@  comment  XXX deductible ? check it  -File: hledger_csv.5.info,  Node: include,  Prev: conditional block,  Up: CSV RULES+File: hledger_csv.5.info,  Node: include,  Next: newest-first,  Prev: conditional block,  Up: CSV RULES  1.6 include ===========@@ -171,51 +172,131 @@ include common.rules  +File: hledger_csv.5.info,  Node: newest-first,  Prev: include,  Up: CSV RULES++1.7 newest-first+================++'newest-first'++   Consider adding this rule if all of the following are true: you might+be processing just one day of data, your CSV records are in reverse+chronological order (newest first), and you care about preserving the+order of same-day transactions.  It usually isn't needed, because+hledger autodetects the CSV order, but when all CSV records have the+same date it will assume they are oldest first.++ File: hledger_csv.5.info,  Node: CSV TIPS,  Prev: CSV RULES,  Up: Top  2 CSV TIPS ********** -Each generated journal entry will have two postings, to 'account1' and-'account2' respectively.  Currently it's not possible to generate-entries with more than two postings.+* Menu: -   If the CSV has debit/credit amounts in separate fields, assign to the-'amount-in' and 'amount-out' pseudo fields instead of 'amount'.+* CSV ordering::+* CSV accounts::+* CSV amounts::+* CSV balance assertions::+* Reading multiple CSV files:: -   If the CSV has the currency in a separate field, assign that to the-'currency' pseudo field which will be automatically prepended to the-amount.  (Or you can do the same thing with a field assignment.)++File: hledger_csv.5.info,  Node: CSV ordering,  Next: CSV accounts,  Up: CSV TIPS -   If the CSV includes a running balance, you can assign that to the-'balance' pseudo field to generate a balance assertion on 'account1'-whenever the balance field is non-empty.  (Eg to double-check your-bank's balance calculation.)+2.1 CSV ordering+================ +The generated journal entries will be sorted by date.  The order of+same-day entries will be preserved (except in the special case where you+might need 'newest-first', see above).+++File: hledger_csv.5.info,  Node: CSV accounts,  Next: CSV amounts,  Prev: CSV ordering,  Up: CSV TIPS++2.2 CSV accounts+================++Each journal entry will have two postings, to 'account1' and 'account2'+respectively.  It's not yet possible to generate entries with more than+two postings.  It's conventional and recommended to use 'account1' for+the account whose CSV we are reading.+++File: hledger_csv.5.info,  Node: CSV amounts,  Next: CSV balance assertions,  Prev: CSV accounts,  Up: CSV TIPS++2.3 CSV amounts+===============++The 'amount' field sets the amount of the 'account1' posting.++   If the CSV has debit/credit amounts in separate fields, assign to the+'amount-in' and 'amount-out' pseudo fields instead.  (Whichever one has+a value will be used, with appropriate sign.  If both contain a value,+it may not work so well.)+    If an amount value is parenthesised, it will be de-parenthesised and-sign-flipped automatically.+sign-flipped. -   The generated journal entries will be sorted by date.  The original-order of same-day entries will be preserved, usually.+   If an amount value begins with a double minus sign, those will cancel+out and be removed. +   If the CSV has the currency symbol in a separate field, assign that+to the 'currency' pseudo field to have it prepended to the amount.  Or,+you can use a field assignment to 'amount' that interpolates both CSV+fields (giving more control, eg to put the currency symbol on the+right).+ +File: hledger_csv.5.info,  Node: CSV balance assertions,  Next: Reading multiple CSV files,  Prev: CSV amounts,  Up: CSV TIPS++2.4 CSV balance assertions+==========================++If the CSV includes a running balance, you can assign that to the+'balance' pseudo field; whenever the running balance value is non-empty,+it will be asserted as the balance after the 'account1' posting.+++File: hledger_csv.5.info,  Node: Reading multiple CSV files,  Prev: CSV balance assertions,  Up: CSV TIPS++2.5 Reading multiple CSV files+==============================++You can read multiple CSV files at once using multiple '-f' arguments on+the command line, and hledger will look for a correspondingly-named+rules file for each.  Note if you use the '--rules-file' option, this+one rules file will be used for all the CSV files being read.++ Tag Table: Node: Top74-Node: CSV RULES814-Ref: #csv-rules924-Node: skip1167-Ref: #skip1263-Node: date-format1435-Ref: #date-format1564-Node: field list2070-Ref: #field-list2209-Node: field assignment2914-Ref: #field-assignment3071-Node: conditional block3575-Ref: #conditional-block3731-Node: include4627-Ref: #include4738-Node: CSV TIPS4969-Ref: #csv-tips5065+Node: CSV RULES810+Ref: #csv-rules920+Node: skip1182+Ref: #skip1278+Node: date-format1450+Ref: #date-format1579+Node: field list2085+Ref: #field-list2224+Node: field assignment2929+Ref: #field-assignment3086+Node: conditional block3590+Ref: #conditional-block3746+Node: include4642+Ref: #include4774+Node: newest-first5005+Ref: #newest-first5121+Node: CSV TIPS5532+Ref: #csv-tips5628+Node: CSV ordering5746+Ref: #csv-ordering5866+Node: CSV accounts6047+Ref: #csv-accounts6187+Node: CSV amounts6441+Ref: #csv-amounts6589+Node: CSV balance assertions7364+Ref: #csv-balance-assertions7548+Node: Reading multiple CSV files7753+Ref: #reading-multiple-csv-files7925  End Tag Table
doc/other/hledger_csv.5.txt view
@@ -19,7 +19,7 @@        To learn about exporting CSV, see CSV output.  CSV RULES-       The following six kinds of rule can appear in the rules  file,  in  any+       The following seven kinds of rule can appear in the rules file, in  any        order.  Blank lines and lines beginning with # or ; are ignored.     skip@@ -123,33 +123,62 @@               # rules reused with several CSV files               include common.rules +   newest-first+       newest-first++       Consider adding this rule if all of the following are true:  you  might+       be  processing  just  one  day of data, your CSV records are in reverse+       chronological order (newest first), and you care about  preserving  the+       order  of  same-day  transactions.   It  usually  isn't needed, because+       hledger autodetects the CSV order, but when all CSV  records  have  the+       same date it will assume they are oldest first.+ CSV TIPS-       Each generated journal entry will have two postings,  to  account1  and-       account2 respectively.  Currently it's not possible to generate entries-       with more than two postings.+   CSV ordering+       The  generated  journal  entries  will be sorted by date.  The order of+       same-day entries will be preserved (except in the  special  case  where+       you might need newest-first, see above). +   CSV accounts+       Each  journal  entry  will  have two postings, to account1 and account2+       respectively.  It's not yet possible to generate entries with more than+       two  postings.   It's  conventional and recommended to use account1 for+       the account whose CSV we are reading.++   CSV amounts+       The amount field sets the amount of the account1 posting.+        If the CSV has debit/credit amounts in separate fields, assign  to  the-       amount-in and amount-out pseudo fields instead of amount.+       amount-in  and  amount-out pseudo fields instead.  (Whichever one has a+       value will be used, with appropriate sign.  If both contain a value, it+       may not work so well.) -       If  the  CSV  has  the currency in a separate field, assign that to the-       currency pseudo field which will  be  automatically  prepended  to  the-       amount.  (Or you can do the same thing with a field assignment.)+       If  an  amount  value is parenthesised, it will be de-parenthesised and+       sign-flipped. -       If  the CSV includes a running balance, you can assign that to the bal--       ance pseudo field to generate a balance assertion on account1  whenever-       the  balance  field is non-empty.  (Eg to double-check your bank's bal--       ance calculation.)+       If an amount value begins with a double minus sign, those  will  cancel+       out and be removed. -       If an amount value is parenthesised, it will  be  de-parenthesised  and-       sign-flipped automatically.+       If  the CSV has the currency symbol in a separate field, assign that to+       the currency pseudo field to have it prepended to the amount.  Or,  you+       can  use a field assignment to amount that interpolates both CSV fields+       (giving more control, eg to put the currency symbol on the right). -       The  generated  journal  entries  will be sorted by date.  The original-       order of same-day entries will be preserved, usually.+   CSV balance assertions+       If the CSV includes a running balance, you can assign that to the  bal-+       ance  pseudo field; whenever the running balance value is non-empty, it+       will be asserted as the balance after the account1 posting. +   Reading multiple CSV files+       You can read multiple CSV files at once using multiple -f arguments  on+       the  command  line,  and  hledger will look for a correspondingly-named+       rules file for each.  Note if you use the --rules-file option, this one+       rules file will be used for all the CSV files being read.  + 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)  @@ -163,7 +192,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) @@ -171,4 +200,4 @@   -hledger 1.3.1                     August 2017                   hledger_csv(5)+hledger 1.4                     September 2017                  hledger_csv(5)
doc/other/hledger_journal.5 view
@@ -1,6 +1,6 @@ .\"t -.TH "hledger_journal" "5" "August 2017" "hledger 1.3.1" "hledger User Manuals"+.TH "hledger_journal" "5" "September 2017" "hledger 1.4" "hledger User Manuals"   @@ -53,6 +53,10 @@ \ \ \ \ expenses:supplies\ \ \ \ \ $1\ \ \ \ ;\ <\-\ this\ transaction\ debits\ two\ expense\ accounts \ \ \ \ assets:cash\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ;\ <\-\ $\-2\ inferred +2008/10/01\ take\ a\ loan+\ \ \ \ assets:bank:checking\ \ $1+\ \ \ \ liabilities:debts\ \ \ \ $\-1+ 2008/12/31\ *\ pay\ off\ \ \ \ \ \ \ \ \ \ \ \ ;\ <\-\ an\ optional\ *\ or\ !\ after\ the\ date\ means\ "cleared"\ (or\ anything\ you\ want) \ \ \ \ liabilities:debts\ \ \ \ \ $1 \ \ \ \ assets:bank:checking@@ -73,7 +77,10 @@ parentheses) .IP \[bu] 2 (optional) a transaction description (any remaining text until end of-line)+line or a semicolon)+.IP \[bu] 2+(optional) a transaction comment (any remaining text following a+semicolon until end of line) .PP Then comes zero or more (but usually at least 2) indented lines representing...@@ -296,6 +303,20 @@ at your bank, \f[C]\-U\f[] to see things which will probably hit your bank soon (like uncashed checks), and no flags to see the most up\-to\-date state of your finances.+.SS Description+.PP+A transaction\[aq]s description is the rest of the line following the+date and status mark (or until a comment begins).+Sometimes called the "narration" in traditional bookkeeping, it can be+used for whatever you wish, or left blank.+Transaction descriptions can be queried, unlike comments.+.SS Payee and note+.PP+You can optionally include a \f[C]|\f[] (pipe) character in a+description to subdivide it into a payee/payer name on the left and+additional notes on the right.+This may be worthwhile if you need to do more precise querying and+pivoting by payee. .SS Account names .PP Account names typically have several parts separated by a full colon,@@ -793,24 +814,6 @@ .PP Tags are like Ledger\[aq]s metadata feature, except hledger\[aq]s tag values are simple strings.-.SS Implicit tags-.PP-Some predefined "implicit" tags are also provided:-.IP \[bu] 2-\f[C]code\f[] \- the transaction\[aq]s code field-.IP \[bu] 2-\f[C]description\f[] \- the transaction\[aq]s description-.IP \[bu] 2-\f[C]payee\f[] \- the part of description before \f[C]|\f[], or all of-it-.IP \[bu] 2-\f[C]note\f[] \- the part of description after \f[C]|\f[], or all of it-.PP-\f[C]payee\f[] and \f[C]note\f[] support descriptions written in a-special \f[C]PAYEE\ |\ NOTE\f[] format, accessing the parts before and-after the pipe character respectively.-For descriptions not containing a pipe character they are the same as-\f[C]description\f[]. .SS Directives .SS Account aliases .PP@@ -878,9 +881,7 @@ replaced by REPLACEMENT. If REGEX contains parenthesised match groups, these can be referenced by the usual numeric backreferences in REPLACEMENT.-Note, currently regular expression aliases may cause noticeable-slow\-downs.-(And if you use Ledger on your hledger file, they will be ignored.) Eg:+Eg: .IP .nf \f[C]@@ -888,6 +889,9 @@ #\ rewrites\ "assets:bank:wells\ fargo:checking"\ to\ \ "assets:wells\ fargo\ checking" \f[] .fi+.PP+Also note that REPLACEMENT continues to the end of line (or on command+line, to end of option argument), so it can contain trailing whitespace. .SS Multiple aliases .PP You can define as many aliases as you like using directives or@@ -1119,6 +1123,11 @@ Text Wrangler \  T}@T{ https://github.com/ledger/ledger/wiki/Editing\-Ledger\-files\-with\-TextWrangler+T}+T{+Visual Studio Code+T}@T{+https://marketplace.visualstudio.com/items?itemName=mark\-hansen.hledger\-vscode T} .TE 
doc/other/hledger_journal.5.info view
@@ -4,8 +4,8 @@  File: hledger_journal.5.info,  Node: Top,  Next: FILE FORMAT,  Up: (dir) -hledger_journal(5) hledger 1.3.1-********************************+hledger_journal(5) hledger 1.4+******************************  hledger's usual data source is a plain text file containing journal entries in hledger journal format.  This file represents a standard@@ -46,6 +46,10 @@     expenses:supplies     $1    ; <- this transaction debits two expense accounts     assets:cash                 ; <- $-2 inferred +2008/10/01 take a loan+    assets:bank:checking  $1+    liabilities:debts    $-1+ 2008/12/31 * pay off            ; <- an optional * or ! after the date means "cleared" (or anything you want)     liabilities:debts     $1     assets:bank:checking@@ -67,6 +71,7 @@ * Postings:: * Dates:: * Status::+* Description:: * Account names:: * Amounts:: * Virtual Postings::@@ -92,7 +97,9 @@    * (optional) a transaction code (any short number or text, enclosed      in parentheses)    * (optional) a transaction description (any remaining text until end-     of line)+     of line or a semicolon)+   * (optional) a transaction comment (any remaining text following a+     semicolon until end of line)     Then comes zero or more (but usually at least 2) indented lines representing...@@ -227,7 +234,7 @@ transaction and DATE2 infers its year from DATE.  -File: hledger_journal.5.info,  Node: Status,  Next: Account names,  Prev: Dates,  Up: FILE FORMAT+File: hledger_journal.5.info,  Node: Status,  Next: Description,  Prev: Dates,  Up: FILE FORMAT  1.4 Status ==========@@ -277,9 +284,35 @@ your finances.  -File: hledger_journal.5.info,  Node: Account names,  Next: Amounts,  Prev: Status,  Up: FILE FORMAT+File: hledger_journal.5.info,  Node: Description,  Next: Account names,  Prev: Status,  Up: FILE FORMAT -1.5 Account names+1.5 Description+===============++A transaction's description is the rest of the line following the date+and status mark (or until a comment begins).  Sometimes called the+"narration" in traditional bookkeeping, it can be used for whatever you+wish, or left blank.  Transaction descriptions can be queried, unlike+comments.+* Menu:++* Payee and note::+++File: hledger_journal.5.info,  Node: Payee and note,  Up: Description++1.5.1 Payee and note+--------------------++You can optionally include a '|' (pipe) character in a description to+subdivide it into a payee/payer name on the left and additional notes on+the right.  This may be worthwhile if you need to do more precise+querying and pivoting by payee.+++File: hledger_journal.5.info,  Node: Account names,  Next: Amounts,  Prev: Description,  Up: FILE FORMAT++1.6 Account names =================  Account names typically have several parts separated by a full colon,@@ -297,7 +330,7 @@  File: hledger_journal.5.info,  Node: Amounts,  Next: Virtual Postings,  Prev: Account names,  Up: FILE FORMAT -1.6 Amounts+1.7 Amounts ===========  After the account name, there is usually an amount.  Important: between@@ -352,7 +385,7 @@  File: hledger_journal.5.info,  Node: Virtual Postings,  Next: Balance Assertions,  Prev: Amounts,  Up: FILE FORMAT -1.7 Virtual Postings+1.8 Virtual Postings ====================  When you parenthesise the account name in a posting, we call that a@@ -387,7 +420,7 @@  File: hledger_journal.5.info,  Node: Balance Assertions,  Next: Balance Assignments,  Prev: Virtual Postings,  Up: FILE FORMAT -1.8 Balance Assertions+1.9 Balance Assertions ======================  hledger supports Ledger-style balance assertions in journal files.@@ -421,7 +454,7 @@  File: hledger_journal.5.info,  Node: Assertions and ordering,  Next: Assertions and included files,  Up: Balance Assertions -1.8.1 Assertions and ordering+1.9.1 Assertions and ordering -----------------------------  hledger sorts an account's postings and assertions first by date and@@ -440,7 +473,7 @@  File: hledger_journal.5.info,  Node: Assertions and included files,  Next: Assertions and multiple -f options,  Prev: Assertions and ordering,  Up: Balance Assertions -1.8.2 Assertions and included files+1.9.2 Assertions and included files -----------------------------------  With included files, things are a little more complicated.  Including@@ -452,7 +485,7 @@  File: hledger_journal.5.info,  Node: Assertions and multiple -f options,  Next: Assertions and commodities,  Prev: Assertions and included files,  Up: Balance Assertions -1.8.3 Assertions and multiple -f options+1.9.3 Assertions and multiple -f options ----------------------------------------  Balance assertions don't work well across files specified with multiple@@ -461,7 +494,7 @@  File: hledger_journal.5.info,  Node: Assertions and commodities,  Next: Assertions and subaccounts,  Prev: Assertions and multiple -f options,  Up: Balance Assertions -1.8.4 Assertions and commodities+1.9.4 Assertions and commodities --------------------------------  The asserted balance must be a simple single-commodity amount, and in@@ -480,7 +513,7 @@  File: hledger_journal.5.info,  Node: Assertions and subaccounts,  Next: Assertions and virtual postings,  Prev: Assertions and commodities,  Up: Balance Assertions -1.8.5 Assertions and subaccounts+1.9.5 Assertions and subaccounts --------------------------------  Balance assertions do not count the balance from subaccounts; they check@@ -503,7 +536,7 @@  File: hledger_journal.5.info,  Node: Assertions and virtual postings,  Prev: Assertions and subaccounts,  Up: Balance Assertions -1.8.6 Assertions and virtual postings+1.9.6 Assertions and virtual postings -------------------------------------  Balance assertions are checked against all postings, both real and@@ -513,8 +546,8 @@  File: hledger_journal.5.info,  Node: Balance Assignments,  Next: Prices,  Prev: Balance Assertions,  Up: FILE FORMAT -1.9 Balance Assignments-=======================+1.10 Balance Assignments+========================  Ledger-style balance assignments are also supported.  These are like balance assertions, but with no posting amount on the left side of the@@ -546,7 +579,7 @@  File: hledger_journal.5.info,  Node: Prices,  Next: Comments,  Prev: Balance Assignments,  Up: FILE FORMAT -1.10 Prices+1.11 Prices ===========  * Menu:@@ -557,7 +590,7 @@  File: hledger_journal.5.info,  Node: Transaction prices,  Next: Market prices,  Up: Prices -1.10.1 Transaction prices+1.11.1 Transaction prices -------------------------  Within a transaction, you can note an amount's price in another@@ -618,7 +651,7 @@  File: hledger_journal.5.info,  Node: Market prices,  Prev: Transaction prices,  Up: Prices -1.10.2 Market prices+1.11.2 Market prices --------------------  Market prices are not tied to a particular transaction; they represent@@ -647,7 +680,7 @@  File: hledger_journal.5.info,  Node: Comments,  Next: Tags,  Prev: Prices,  Up: FILE FORMAT -1.11 Comments+1.12 Comments =============  Lines in the journal beginning with a semicolon (';') or hash ('#') or@@ -687,7 +720,7 @@  File: hledger_journal.5.info,  Node: Tags,  Next: Directives,  Prev: Comments,  Up: FILE FORMAT -1.12 Tags+1.13 Tags =========  Tags are a way to add extra labels or labelled data to postings and@@ -726,32 +759,11 @@     Tags are like Ledger's metadata feature, except hledger's tag values are simple strings.-* Menu: -* Implicit tags::- -File: hledger_journal.5.info,  Node: Implicit tags,  Up: Tags--1.12.1 Implicit tags-----------------------Some predefined "implicit" tags are also provided:--   * 'code' - the transaction's code field-   * 'description' - the transaction's description-   * 'payee' - the part of description before '|', or all of it-   * 'note' - the part of description after '|', or all of it--   'payee' and 'note' support descriptions written in a special 'PAYEE |-NOTE' format, accessing the parts before and after the pipe character-respectively.  For descriptions not containing a pipe character they are-the same as 'description'.-- File: hledger_journal.5.info,  Node: Directives,  Prev: Tags,  Up: FILE FORMAT -1.13 Directives+1.14 Directives ===============  * Menu:@@ -768,7 +780,7 @@  File: hledger_journal.5.info,  Node: Account aliases,  Next: account directive,  Up: Directives -1.13.1 Account aliases+1.14.1 Account aliases ----------------------  You can define aliases which rewrite your account names (after reading@@ -793,7 +805,7 @@  File: hledger_journal.5.info,  Node: Basic aliases,  Next: Regex aliases,  Up: Account aliases -1.13.1.1 Basic aliases+1.14.1.1 Basic aliases ......................  To set an account alias, use the 'alias' directive in your journal file.@@ -816,7 +828,7 @@  File: hledger_journal.5.info,  Node: Regex aliases,  Next: Multiple aliases,  Prev: Basic aliases,  Up: Account aliases -1.13.1.2 Regex aliases+1.14.1.2 Regex aliases ......................  There is also a more powerful variant that uses a regular expression,@@ -829,17 +841,19 @@    REGEX is a case-insensitive regular expression.  Anywhere it matches inside an account name, the matched part will be replaced by REPLACEMENT. If REGEX contains parenthesised match groups, these can be-referenced by the usual numeric backreferences in REPLACEMENT. Note,-currently regular expression aliases may cause noticeable slow-downs.-(And if you use Ledger on your hledger file, they will be ignored.)  Eg:+referenced 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+whitespace.+  File: hledger_journal.5.info,  Node: Multiple aliases,  Next: end aliases,  Prev: Regex aliases,  Up: Account aliases -1.13.1.3 Multiple aliases+1.14.1.3 Multiple aliases .........................  You can define as many aliases as you like using directives or@@ -855,7 +869,7 @@  File: hledger_journal.5.info,  Node: end aliases,  Prev: Multiple aliases,  Up: Account aliases -1.13.1.4 end aliases+1.14.1.4 end aliases ....................  You can clear (forget) all currently defined aliases with the 'end@@ -866,7 +880,7 @@  File: hledger_journal.5.info,  Node: account directive,  Next: apply account directive,  Prev: Account aliases,  Up: Directives -1.13.2 account directive+1.14.2 account directive ------------------------  The 'account' directive predefines account names, as in Ledger and@@ -887,7 +901,7 @@  File: hledger_journal.5.info,  Node: apply account directive,  Next: Multi-line comments,  Prev: account directive,  Up: Directives -1.13.3 apply account directive+1.14.3 apply account directive ------------------------------  You can specify a parent account which will be prepended to all accounts@@ -923,7 +937,7 @@  File: hledger_journal.5.info,  Node: Multi-line comments,  Next: commodity directive,  Prev: apply account directive,  Up: Directives -1.13.4 Multi-line comments+1.14.4 Multi-line comments --------------------------  A line containing just 'comment' starts a multi-line comment, and a line@@ -932,7 +946,7 @@  File: hledger_journal.5.info,  Node: commodity directive,  Next: Default commodity,  Prev: Multi-line comments,  Up: Directives -1.13.5 commodity directive+1.14.5 commodity directive --------------------------  The 'commodity' directive predefines commodities (currently this is just@@ -964,7 +978,7 @@  File: hledger_journal.5.info,  Node: Default commodity,  Next: Default year,  Prev: commodity directive,  Up: Directives -1.13.6 Default commodity+1.14.6 Default commodity ------------------------  The D directive sets a default commodity (and display format), to be@@ -984,7 +998,7 @@  File: hledger_journal.5.info,  Node: Default year,  Next: Including other files,  Prev: Default commodity,  Up: Directives -1.13.7 Default year+1.14.7 Default year -------------------  You can set a default year to be used for subsequent dates which don't@@ -1010,7 +1024,7 @@  File: hledger_journal.5.info,  Node: Including other files,  Prev: Default year,  Up: Directives -1.13.8 Including other files+1.14.8 Including other files ----------------------------  You can pull in the content of additional journal files by writing an@@ -1043,87 +1057,91 @@ Sublime Text      https://github.com/ledger/ledger/wiki/Using-Sublime-Text Textmate          https://github.com/ledger/ledger/wiki/Using-TextMate-2 Text Wrangler     https://github.com/ledger/ledger/wiki/Editing-Ledger-files-with-TextWrangler+Visual Studio     https://marketplace.visualstudio.com/items?itemName=mark-hansen.hledger-vscode+Code   Tag Table: Node: Top78-Node: FILE FORMAT2296-Ref: #file-format2422-Node: Transactions2629-Ref: #transactions2752-Node: Postings3317-Ref: #postings3446-Node: Dates4441-Ref: #dates4558-Node: Simple dates4623-Ref: #simple-dates4751-Node: Secondary dates5117-Ref: #secondary-dates5273-Node: Posting dates6836-Ref: #posting-dates6967-Node: Status8341-Ref: #status8465-Node: Account names10179-Ref: #account-names10319-Node: Amounts10806-Ref: #amounts10944-Node: Virtual Postings13045-Ref: #virtual-postings13206-Node: Balance Assertions14426-Ref: #balance-assertions14603-Node: Assertions and ordering15499-Ref: #assertions-and-ordering15687-Node: Assertions and included files16387-Ref: #assertions-and-included-files16630-Node: Assertions and multiple -f options16963-Ref: #assertions-and-multiple--f-options17219-Node: Assertions and commodities17351-Ref: #assertions-and-commodities17588-Node: Assertions and subaccounts18284-Ref: #assertions-and-subaccounts18518-Node: Assertions and virtual postings19039-Ref: #assertions-and-virtual-postings19248-Node: Balance Assignments19390-Ref: #balance-assignments19559-Node: Prices20678-Ref: #prices20813-Node: Transaction prices20864-Ref: #transaction-prices21011-Node: Market prices23167-Ref: #market-prices23304-Node: Comments24264-Ref: #comments24388-Node: Tags25501-Ref: #tags25621-Node: Implicit tags27050-Ref: #implicit-tags27158-Node: Directives27675-Ref: #directives27790-Node: Account aliases27983-Ref: #account-aliases28129-Node: Basic aliases28733-Ref: #basic-aliases28878-Node: Regex aliases29568-Ref: #regex-aliases29738-Node: Multiple aliases30453-Ref: #multiple-aliases30627-Node: end aliases31125-Ref: #end-aliases31267-Node: account directive31368-Ref: #account-directive31550-Node: apply account directive31846-Ref: #apply-account-directive32044-Node: Multi-line comments32703-Ref: #multi-line-comments32895-Node: commodity directive33023-Ref: #commodity-directive33209-Node: Default commodity34081-Ref: #default-commodity34256-Node: Default year34793-Ref: #default-year34960-Node: Including other files35383-Ref: #including-other-files35542-Node: EDITOR SUPPORT35939-Ref: #editor-support36059+Node: FILE FORMAT2374+Ref: #file-format2500+Node: Transactions2723+Ref: #transactions2846+Node: Postings3530+Ref: #postings3659+Node: Dates4654+Ref: #dates4771+Node: Simple dates4836+Ref: #simple-dates4964+Node: Secondary dates5330+Ref: #secondary-dates5486+Node: Posting dates7049+Ref: #posting-dates7180+Node: Status8554+Ref: #status8676+Node: Description10390+Ref: #description10530+Node: Payee and note10849+Ref: #payee-and-note10965+Node: Account names11207+Ref: #account-names11352+Node: Amounts11839+Ref: #amounts11977+Node: Virtual Postings14078+Ref: #virtual-postings14239+Node: Balance Assertions15459+Ref: #balance-assertions15636+Node: Assertions and ordering16532+Ref: #assertions-and-ordering16720+Node: Assertions and included files17420+Ref: #assertions-and-included-files17663+Node: Assertions and multiple -f options17996+Ref: #assertions-and-multiple--f-options18252+Node: Assertions and commodities18384+Ref: #assertions-and-commodities18621+Node: Assertions and subaccounts19317+Ref: #assertions-and-subaccounts19551+Node: Assertions and virtual postings20072+Ref: #assertions-and-virtual-postings20281+Node: Balance Assignments20423+Ref: #balance-assignments20594+Node: Prices21713+Ref: #prices21848+Node: Transaction prices21899+Ref: #transaction-prices22046+Node: Market prices24202+Ref: #market-prices24339+Node: Comments25299+Ref: #comments25423+Node: Tags26536+Ref: #tags26656+Node: Directives28058+Ref: #directives28173+Node: Account aliases28366+Ref: #account-aliases28512+Node: Basic aliases29116+Ref: #basic-aliases29261+Node: Regex aliases29951+Ref: #regex-aliases30121+Node: Multiple aliases30839+Ref: #multiple-aliases31013+Node: end aliases31511+Ref: #end-aliases31653+Node: account directive31754+Ref: #account-directive31936+Node: apply account directive32232+Ref: #apply-account-directive32430+Node: Multi-line comments33089+Ref: #multi-line-comments33281+Node: commodity directive33409+Ref: #commodity-directive33595+Node: Default commodity34467+Ref: #default-commodity34642+Node: Default year35179+Ref: #default-year35346+Node: Including other files35769+Ref: #including-other-files35928+Node: EDITOR SUPPORT36325+Ref: #editor-support36445  End Tag Table
doc/other/hledger_journal.5.txt view
@@ -47,6 +47,10 @@                   expenses:supplies     $1    ; <- this transaction debits two expense accounts                   assets:cash                 ; <- $-2 inferred +              2008/10/01 take a loan+                  assets:bank:checking  $1+                  liabilities:debts    $-1+               2008/12/31 * pay off            ; <- an optional * or ! after the date means "cleared" (or anything you want)                   liabilities:debts     $1                   assets:bank:checking@@ -64,59 +68,62 @@          parentheses)         o (optional) a transaction description (any remaining text until end of-         line)+         line or a semicolon) -       Then comes zero or more (but usually at least 2) indented lines  repre-+       o (optional) a transaction comment  (any  remaining  text  following  a+         semicolon until end of line)++       Then  comes zero or more (but usually at least 2) indented lines repre-        senting...     Postings-       A  posting  is an addition of some amount to, or removal of some amount-       from, an account.  Each posting line begins with at least one space  or+       A posting is an addition of some amount to, or removal of  some  amount+       from,  an account.  Each posting line begins with at least one space or        tab (2 or 4 spaces is common), followed by:         o (optional) a status character (empty, !, or *), followed by a space -       o (required)  an  account  name (any text, optionally containing single+       o (required) an account name (any text,  optionally  containing  single          spaces, until end of line or a double space)         o (optional) two or more spaces or tabs followed by an amount. -       Positive amounts are being added to the account, negative  amounts  are+       Positive  amounts  are being added to the account, negative amounts are        being removed.         The amounts within a transaction must always sum up to zero.  As a con--       venience, one amount may be left blank; it will be inferred  so  as  to+       venience,  one  amount  may be left blank; it will be inferred so as to        balance the transaction. -       Be  sure  to  note the unusual two-space delimiter between account name-       and amount.  This makes it easy to write account names containing  spa--       ces.   But if you accidentally leave only one space (or tab) before the+       Be sure to note the unusual two-space delimiter  between  account  name+       and  amount.  This makes it easy to write account names containing spa-+       ces.  But if you accidentally leave only one space (or tab) before  the        amount, the amount will be considered part of the account name.     Dates    Simple dates-       Within a journal file, transaction dates use Y/M/D (or Y-M-D or  Y.M.D)-       Leading  zeros are optional.  The year may be omitted, in which case it-       will be inferred from  the  context  -  the  current  transaction,  the-       default  year  set  with  a default year directive, or the current date-       when the command is run.  Some examples: 2010/01/31, 1/31,  2010-01-31,+       Within  a journal file, transaction dates use Y/M/D (or Y-M-D or Y.M.D)+       Leading zeros are optional.  The year may be omitted, in which case  it+       will  be  inferred  from  the  context  -  the current transaction, the+       default year set with a default year directive,  or  the  current  date+       when  the command is run.  Some examples: 2010/01/31, 1/31, 2010-01-31,        2010.1.31.     Secondary dates-       Real-life  transactions  sometimes  involve more than one date - eg the+       Real-life transactions sometimes involve more than one date  -  eg  the        date you write a cheque, and the date it clears in your bank.  When you-       want  to  model  this,  eg  for more accurate balances, you can specify-       individual posting dates, which I recommend.  Or, you can use the  sec--       ondary  dates  (aka  auxiliary/effective  dates) feature, supported for+       want to model this, eg for more  accurate  balances,  you  can  specify+       individual  posting dates, which I recommend.  Or, you can use the sec-+       ondary dates (aka auxiliary/effective  dates)  feature,  supported  for        compatibility with Ledger.         A secondary date can be written after the primary date, separated by an-       equals  sign.   The  primary date, on the left, is used by default; the-       secondary date, on the right, is used when the --date2 flag  is  speci-+       equals sign.  The primary date, on the left, is used  by  default;  the+       secondary  date,  on the right, is used when the --date2 flag is speci-        fied (--aux-date or --effective also work). -       The  meaning of secondary dates is up to you, but it's best to follow a-       consistent rule.  Eg write the bank's clearing  date  as  primary,  and+       The meaning of secondary dates is up to you, but it's best to follow  a+       consistent  rule.   Eg  write  the bank's clearing date as primary, and        when needed, the date the transaction was initiated as secondary.         Here's an example.  Note that a secondary date will use the year of the@@ -132,18 +139,18 @@               $ hledger register checking --date2               2010/02/19 movie ticket         assets:checking                $-10         $-10 -       Secondary dates require some effort; you must use them consistently  in+       Secondary  dates require some effort; you must use them consistently in        your journal entries and remember whether to use or not use the --date2        flag for your reports.  They are included in hledger for Ledger compat--       ibility,  but  posting  dates  are  a  more powerful and less confusing+       ibility, but posting dates are  a  more  powerful  and  less  confusing        alternative.     Posting dates-       You can give individual postings a different  date  from  their  parent-       transaction,  by  adding a posting comment containing a tag (see below)+       You  can  give  individual  postings a different date from their parent+       transaction, by adding a posting comment containing a tag  (see  below)        like date:DATE.  This is probably the best way to control posting dates-       precisely.   Eg  in  this  example  the  expense  should  appear in May-       reports, and the deduction from checking should be reported on 6/1  for+       precisely.  Eg in  this  example  the  expense  should  appear  in  May+       reports,  and the deduction from checking should be reported on 6/1 for        easy bank reconciliation:                2015/5/30@@ -156,22 +163,22 @@               $ hledger -f t.j register checking               2015/06/01                      assets:checking               $-10          $-10 -       DATE  should be a simple date; if the year is not specified it will use-       the year of the transaction's date.  You can  set  the  secondary  date-       similarly,  with  date2:DATE2.   The  date:  or date2: tags must have a-       valid simple date value if they are present, eg a  date:  tag  with  no+       DATE should be a simple date; if the year is not specified it will  use+       the  year  of  the  transaction's date.  You can set the secondary date+       similarly, with date2:DATE2.  The date: or  date2:  tags  must  have  a+       valid  simple  date  value  if they are present, eg a date: tag with no        value is not allowed.         Ledger's earlier, more compact bracketed date syntax is also supported:-       [DATE], [DATE=DATE2] or [=DATE2].  hledger will attempt  to  parse  any+       [DATE],  [DATE=DATE2]  or  [=DATE2].  hledger will attempt to parse any        square-bracketed sequence of the 0123456789/-.= characters in this way.-       With this syntax, DATE infers its year from the transaction  and  DATE2+       With  this  syntax, DATE infers its year from the transaction and DATE2        infers its year from DATE.     Status-       Transactions,  or  individual postings within a transaction, can have a-       status mark,  which  is  a  single  character  before  the  transaction-       description  or  posting  account  name,  separated from it by a space,+       Transactions, or individual postings within a transaction, can  have  a+       status  mark,  which  is  a  single  character  before  the transaction+       description or posting account name, separated  from  it  by  a  space,        indicating one of three statuses:  @@ -181,39 +188,52 @@        !        pending        *        cleared -       When reporting, you  can  filter  by  status  with  the  -U/--unmarked,-       -P/--pending,  and  -C/--cleared  flags;  or the status:, status:!, and+       When  reporting,  you  can  filter  by  status  with the -U/--unmarked,+       -P/--pending, and -C/--cleared flags; or  the  status:,  status:!,  and        status:* queries; or the U, P, C keys in hledger-ui. -       Note, in Ledger and in older versions of hledger, the "unmarked"  state-       is  called  "uncleared".   As  of  hledger  1.3  we  have renamed it to+       Note,  in Ledger and in older versions of hledger, the "unmarked" state+       is called "uncleared".  As  of  hledger  1.3  we  have  renamed  it  to        unmarked for clarity. -       To replicate Ledger and old hledger's behaviour of also matching  pend-+       To  replicate Ledger and old hledger's behaviour of also matching pend-        ing, combine -U and -P. -       Status  marks  are optional, but can be helpful eg for reconciling with+       Status marks are optional, but can be helpful eg for  reconciling  with        real-world accounts.  Some editor modes provide highlighting and short--       cuts  for working with status.  Eg in Emacs ledger-mode, you can toggle+       cuts for working with status.  Eg in Emacs ledger-mode, you can  toggle        transaction status with C-c C-e, or posting status with C-c C-c. -       What "uncleared", "pending", and "cleared" actually mean is up to  you.+       What  "uncleared", "pending", and "cleared" actually mean is up to you.        Here's one suggestion:          status       meaning        --------------------------------------------------------------------------        uncleared    recorded but not yet reconciled; needs review-       pending      tentatively  reconciled  (if needed, eg during a big recon-+       pending      tentatively reconciled (if needed, eg during a  big  recon-                     ciliation)-       cleared      complete, reconciled as far  as  possible,  and  considered+       cleared      complete,  reconciled  as  far  as possible, and considered                     correct -       With  this scheme, you would use -PC to see the current balance at your-       bank, -U to see things which will probably hit  your  bank  soon  (like+       With this scheme, you would use -PC to see the current balance at  your+       bank,  -U  to  see  things which will probably hit your bank soon (like        uncashed checks), and no flags to see the most up-to-date state of your        finances. +   Description+       A  transaction's description is the rest of the line following the date+       and status mark (or until a  comment  begins).   Sometimes  called  the+       "narration" in traditional bookkeeping, it can be used for whatever you+       wish, or left blank.  Transaction descriptions can be  queried,  unlike+       comments.++   Payee and note+       You  can  optionally  include  a | (pipe) character in a description to+       subdivide it into a payee/payer name on the left and  additional  notes+       on  the  right.   This may be worthwhile if you need to do more precise+       querying and pivoting by payee.+    Account names        Account names typically have several parts separated by a  full  colon,        from  which hledger derives a hierarchical chart of accounts.  They can@@ -577,25 +597,9 @@        Tags are like Ledger's metadata feature, except  hledger's  tag  values        are simple strings. -   Implicit tags-       Some predefined "implicit" tags are also provided:--       o code - the transaction's code field--       o description - the transaction's description--       o payee - the part of description before |, or all of it--       o note - the part of description after |, or all of it--       payee  and  note support descriptions written in a special PAYEE | NOTE-       format, accessing the parts before and after the pipe character respec--       tively.   For descriptions not containing a pipe character they are the-       same as description.-    Directives    Account aliases-       You can define aliases which rewrite your account names (after  reading+       You  can define aliases which rewrite your account names (after reading        the journal, before generating reports).  hledger's account aliases can        be useful for: @@ -612,8 +616,8 @@        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@@ -621,31 +625,33 @@        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--       erenced by the usual numeric backreferences in REPLACEMENT.  Note, cur--       rently  regular  expression  aliases  may  cause noticeable slow-downs.-       (And if you use Ledger on your hledger file, they will be ignored.) Eg:+       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-+       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@@ -811,7 +817,11 @@                           ing-Ledger-files-with-TextWrangler  +       Visual    Studio   https://marketplace.visualstudio.com/items?item-+       Code               Name=mark-hansen.hledger-vscode ++ REPORTING BUGS        Report  bugs at http://bugs.hledger.org (or on the #hledger IRC channel        or hledger mail list)@@ -835,4 +845,4 @@   -hledger 1.3.1                     August 2017               hledger_journal(5)+hledger 1.4                     September 2017              hledger_journal(5)
doc/other/hledger_timeclock.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_timeclock" "5" "August 2017" "hledger 1.3.1" "hledger User Manuals"+.TH "hledger_timeclock" "5" "September 2017" "hledger 1.4" "hledger User Manuals"   
doc/other/hledger_timeclock.5.info view
@@ -4,8 +4,8 @@  File: hledger_timeclock.5.info,  Node: Top,  Up: (dir) -hledger_timeclock(5) hledger 1.3.1-**********************************+hledger_timeclock(5) hledger 1.4+********************************  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
doc/other/hledger_timeclock.5.txt view
@@ -79,4 +79,4 @@   -hledger 1.3.1                     August 2017             hledger_timeclock(5)+hledger 1.4                     September 2017            hledger_timeclock(5)
doc/other/hledger_timedot.5 view
@@ -1,5 +1,5 @@ -.TH "hledger_timedot" "5" "August 2017" "hledger 1.3.1" "hledger User Manuals"+.TH "hledger_timedot" "5" "September 2017" "hledger 1.4" "hledger User Manuals"   @@ -9,17 +9,17 @@ .SH DESCRIPTION .PP Timedot is a plain text format for logging dated, categorised quantities-(eg time), supported by hledger.+(of time, usually), supported by hledger. It is convenient for approximate and retroactive time logging, eg when the real\-time clock\-in/out required with a timeclock file is too precise or too interruptive. It can be formatted like a bar chart, making clear at a glance where time was spent. .PP-Though called "timedot", the format does not specify the commodity being-logged, so could represent other dated, quantifiable things.-Eg you could record a single\-entry journal of financial transactions,-perhaps slightly more conveniently than with hledger_journal(5) format.+Though called "timedot", this format is read by hledger as commodityless+quantities, so it could be used to represent dated quantities other than+time.+In the docs below we\[aq]ll assume it\[aq]s time. .SH FILE FORMAT .PP A timedot file contains a series of day entries.@@ -27,16 +27,26 @@ pairs, one per line. Dates are hledger\-style simple dates (see hledger_journal(5)). Categories are hledger\-style account names, optionally indented.-There must be at least two spaces between the category and the quantity.-Quantities can be written in two ways:-.IP "1." 3-a series of dots (period characters).-Each dot represents "a quarter" \- eg, a quarter hour.-Spaces can be used to group dots into hours, for easier counting.-.IP "2." 3-a number (integer or decimal), representing "units" \- eg, hours.-A good alternative when dots are cumbersome.-(A number also can record negative quantities.)+As in a hledger journal, there must be at least two spaces between the+category (account name) and the quantity.+.PP+Quantities can be written as:+.IP \[bu] 2+a sequence of dots (.) representing quarter hours.+Spaces may optionally be used for grouping and readability.+Eg: ....+\&..+.IP \[bu] 2+an integral or decimal number, representing hours.+Eg: 1.5+.IP \[bu] 2+an integral or decimal number immediately followed by a unit symbol+\f[C]s\f[], \f[C]m\f[], \f[C]h\f[], \f[C]d\f[], \f[C]w\f[], \f[C]mo\f[],+or \f[C]y\f[], representing seconds, minutes, hours, days weeks, months+or years respectively.+Eg: 90m.+The following equivalencies are assumed, currently: 1m = 60s, 1h = 60m,+1d = 24h, 1w = 7d, 1mo = 30d, 1y=365d. .PP Blank lines and lines beginning with #, ; or * are ignored. An example:
doc/other/hledger_timedot.5.info view
@@ -4,20 +4,19 @@  File: hledger_timedot.5.info,  Node: Top,  Next: FILE FORMAT,  Up: (dir) -hledger_timedot(5) hledger 1.3.1-********************************+hledger_timedot(5) hledger 1.4+******************************  Timedot is a plain text format for logging dated, categorised quantities-(eg time), supported by hledger.  It is convenient for approximate and-retroactive time logging, eg when the real-time clock-in/out required-with a timeclock file is too precise or too interruptive.  It can be-formatted like a bar chart, making clear at a glance where time was-spent.+(of time, usually), supported by hledger.  It is convenient for+approximate and retroactive time logging, eg when the real-time+clock-in/out required with a timeclock file is too precise or too+interruptive.  It can be formatted like a bar chart, making clear at a+glance where time was spent. -   Though called "timedot", the format does not specify the commodity-being logged, so could represent other dated, quantifiable things.  Eg-you could record a single-entry journal of financial transactions,-perhaps slightly more conveniently than with hledger_journal(5) format.+   Though called "timedot", this format is read by hledger as+commodityless quantities, so it could be used to represent dated+quantities other than time.  In the docs below we'll assume it's time. * Menu:  * FILE FORMAT::@@ -31,18 +30,23 @@ A timedot file contains a series of day entries.  A day entry begins with a date, and is followed by category/quantity pairs, one per line. Dates are hledger-style simple dates (see hledger_journal(5)).-Categories are hledger-style account names, optionally indented.  There-must be at least two spaces between the category and the quantity.-Quantities can be written in two ways:+Categories are hledger-style account names, optionally indented.  As in+a hledger journal, there must be at least two spaces between the+category (account name) and the quantity. -  1. a series of dots (period characters).  Each dot represents "a-     quarter" - eg, a quarter hour.  Spaces can be used to group dots-     into hours, for easier counting.+   Quantities can be written as: -  2. a number (integer or decimal), representing "units" - eg, hours.  A-     good alternative when dots are cumbersome.  (A number also can-     record negative quantities.)+   * a sequence of dots (.)  representing quarter hours.  Spaces may+     optionally be used for grouping and readability.  Eg: ....  .. +   * an integral or decimal number, representing hours.  Eg: 1.5++   * an integral or decimal number immediately followed by a unit symbol+     's', 'm', 'h', 'd', 'w', 'mo', or 'y', representing seconds,+     minutes, hours, days weeks, months or years respectively.  Eg: 90m.+     The following equivalencies are assumed, currently: 1m = 60s, 1h =+     60m, 1d = 24h, 1w = 7d, 1mo = 30d, 1y=365d.+    Blank lines and lines beginning with #, ; or * are ignored.  An example: @@ -106,7 +110,7 @@  Tag Table: Node: Top78-Node: FILE FORMAT886-Ref: #file-format989+Node: FILE FORMAT809+Ref: #file-format912  End Tag Table
doc/other/hledger_timedot.5.txt view
@@ -8,33 +8,37 @@  DESCRIPTION        Timedot  is  a plain text format for logging dated, categorised quanti--       ties (eg time), supported by hledger.  It is convenient for approximate-       and  retroactive  time  logging,  eg  when  the  real-time clock-in/out-       required with a timeclock file is too precise or too interruptive.   It-       can  be formatted like a bar chart, making clear at a glance where time-       was spent.+       ties (of time, usually), supported by hledger.  It  is  convenient  for+       approximate  and  retroactive  time  logging,  eg  when  the  real-time+       clock-in/out required with a timeclock  file  is  too  precise  or  too+       interruptive.   It can be formatted like a bar chart, making clear at a+       glance where time was spent. -       Though called "timedot", the format  does  not  specify  the  commodity-       being  logged, so could represent other dated, quantifiable things.  Eg-       you could record a single-entry journal of financial transactions, per--       haps slightly more conveniently than with hledger_journal(5) format.+       Though called "timedot", this format is read by hledger  as  commodity-+       less  quantities,  so  it  could  be used to represent dated quantities+       other than time.  In the docs below we'll assume it's time.  FILE FORMAT-       A  timedot  file  contains a series of day entries.  A day entry begins-       with a date, and is followed by category/quantity pairs, one per  line.-       Dates  are  hledger-style simple dates (see hledger_journal(5)).  Cate--       gories are hledger-style account  names,  optionally  indented.   There-       must  be  at  least  two  spaces between the category and the quantity.-       Quantities can be written in two ways:+       A timedot file contains a series of day entries.  A  day  entry  begins+       with  a date, and is followed by category/quantity pairs, one per line.+       Dates are hledger-style simple dates (see  hledger_journal(5)).   Cate-+       gories  are  hledger-style account names, optionally indented.  As in a+       hledger journal, there must be at least two spaces between the category+       (account name) and the quantity. -       1. a series of dots (period characters).  Each dot represents "a  quar--          ter"  -  eg,  a quarter hour.  Spaces can be used to group dots into-          hours, for easier counting.+       Quantities can be written as: -       2. a number (integer or decimal), representing "units" - eg, hours.   A-          good  alternative  when  dots  are  cumbersome.   (A number also can-          record negative quantities.)+       o a  sequence  of  dots  (.)  representing  quarter  hours.  Spaces may+         optionally be used for grouping and readability.  Eg: ....  .. +       o an integral or decimal number, representing hours.  Eg: 1.5++       o an integral or decimal number immediately followed by a  unit  symbol+         s,  m,  h, d, w, mo, or y, representing seconds, minutes, hours, days+         weeks, months or years respectively.  Eg: 90m.  The following equiva-+         lencies  are  assumed,  currently: 1m = 60s, 1h = 60m, 1d = 24h, 1w =+         7d, 1mo = 30d, 1y=365d.+        Blank lines and lines beginning with #, ; or * are ignored.   An  exam-        ple: @@ -120,4 +124,4 @@   -hledger 1.3.1                     August 2017               hledger_timedot(5)+hledger 1.4                     September 2017              hledger_timedot(5)
hledger.cabal view
@@ -3,7 +3,7 @@ -- see: https://github.com/sol/hpack  name:           hledger-version:        1.3.1+version:        1.4 synopsis:       Command-line interface for the hledger accounting tool description:    This is hledger's command-line interface.                 Its basic function is to read a plain text file describing@@ -23,7 +23,7 @@ maintainer:     Simon Michael <simon@joyful.com> license:        GPL-3 license-file:   LICENSE-tested-with:    GHC==7.10.3, GHC==8.0+tested-with:    GHC==7.10.3, GHC==8.0.2, GHC==8.2.1 build-type:     Simple cabal-version:  >= 1.10 @@ -63,11 +63,6 @@   type: git   location: https://github.com/simonmichael/hledger -flag oldtime-  description: If building with time < 1.5, also depend on old-locale. Set automatically by cabal.-  manual: False-  default: False- flag terminfo   description: On POSIX systems, build with the terminfo lib for detecting terminal width.   manual: False@@ -80,26 +75,30 @@  library   ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans-  cpp-options: -DVERSION="1.3.1"+  cpp-options: -DVERSION="1.4"   build-depends:       base >=4.8 && <5     , base-compat >=0.8.1-    , ansi-terminal >= 0.6.2.3 && < 0.7+    , ansi-terminal >= 0.6.2.3 && < 0.8     , directory     , file-embed >=0.0.10 && <0.1     , filepath     , here     , pretty-show >=1.6.4     , process+    , shakespeare >=2.0.2.2 && <2.1     , temporary     , tabular >=0.2 && <0.3-    , hledger-lib >= 1.3.1 && < 1.4+    , time >=1.5+    , utility-ht >= 0.0.13+    , hledger-lib >= 1.4 && < 1.5     , bytestring     , containers     , unordered-containers     , cmdargs >=0.10 && <0.11     , csv     , data-default >=0.5+    , Diff     , hashable >=1.2.4     , haskeline >=0.6 && <=0.8     , HUnit@@ -114,23 +113,6 @@     , text >=0.11     , utf8-string >=0.3.5 && <1.1     , wizards ==1.0.*-  if impl(ghc <7.6)-    build-depends:-        ghc-prim-  if impl(ghc >=7.10)-    build-depends:-        shakespeare >=2.0.2.2 && <2.1-  else-    build-depends:-        shakespeare >=1.0 && <2.1-      , shakespeare-text >=1.0 && <1.2-  if flag(oldtime)-    build-depends:-        time <1.5-      , old-locale-  else-    build-depends:-        time >=1.5   if (!(os(windows))) && (flag(terminfo))     build-depends:         terminfo@@ -139,23 +121,31 @@       Hledger.Cli.Main       Hledger.Cli.CliOptions       Hledger.Cli.DocFiles-      Hledger.Cli.Tests       Hledger.Cli.Utils       Hledger.Cli.Version-      Hledger.Cli.Add-      Hledger.Cli.Accounts-      Hledger.Cli.Balance-      Hledger.Cli.Balancesheet+      Hledger.Cli.Commands+      Hledger.Cli.Commands.Accounts+      Hledger.Cli.Commands.Activity+      Hledger.Cli.Commands.Add+      Hledger.Cli.Commands.Balance+      Hledger.Cli.Commands.Balancesheet+      Hledger.Cli.Commands.Balancesheetequity+      Hledger.Cli.Commands.Cashflow+      Hledger.Cli.Commands.Checkdates+      Hledger.Cli.Commands.Checkdupes+      Hledger.Cli.Commands.Equity+      Hledger.Cli.Commands.Help+      Hledger.Cli.Commands.Import+      Hledger.Cli.Commands.Incomestatement+      Hledger.Cli.Commands.Prices+      Hledger.Cli.Commands.Print+      Hledger.Cli.Commands.Printunique+      Hledger.Cli.Commands.Register+      Hledger.Cli.Commands.Registermatch+      Hledger.Cli.Commands.Rewrite+      Hledger.Cli.Commands.Stats+      Hledger.Cli.Commands.Tags       Hledger.Cli.CompoundBalanceCommand-      Hledger.Cli.Cashflow-      Hledger.Cli.Help-      Hledger.Cli.Histogram-      Hledger.Cli.Incomestatement-      Hledger.Cli.Info-      Hledger.Cli.Man-      Hledger.Cli.Print-      Hledger.Cli.Register-      Hledger.Cli.Stats       Text.Tabular.AsciiWide   other-modules:       Paths_hledger@@ -166,20 +156,23 @@   hs-source-dirs:       app   ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans-  cpp-options: -DVERSION="1.3.1"+  cpp-options: -DVERSION="1.4"   build-depends:       base >=4.8 && <5     , base-compat >=0.8.1-    , ansi-terminal >= 0.6.2.3 && < 0.7+    , ansi-terminal >= 0.6.2.3 && < 0.8     , directory     , file-embed >=0.0.10 && <0.1     , filepath     , here     , pretty-show >=1.6.4     , process+    , shakespeare >=2.0.2.2 && <2.1     , temporary     , tabular >=0.2 && <0.3-    , hledger-lib >= 1.3.1+    , time >=1.5+    , utility-ht >= 0.0.13+    , hledger-lib >= 1.4 && < 1.5     , hledger     , bytestring     , containers@@ -199,28 +192,11 @@     , text >=0.11     , utf8-string >=0.3.5 && <1.1     , wizards ==1.0.*-  if flag(threaded)-    ghc-options: -threaded-  if impl(ghc <7.6)-    build-depends:-        ghc-prim-  if impl(ghc >=7.10)-    build-depends:-        shakespeare >=2.0.2.2 && <2.1-  else-    build-depends:-        shakespeare >=1.0 && <2.1-      , shakespeare-text >=1.0 && <1.2-  if flag(oldtime)-    build-depends:-        time <1.5-      , old-locale-  else-    build-depends:-        time >=1.5   if (!(os(windows))) && (flag(terminfo))     build-depends:         terminfo+  if flag(threaded)+    ghc-options: -threaded   default-language: Haskell2010  test-suite test@@ -229,20 +205,23 @@   hs-source-dirs:       test   ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans-  cpp-options: -DVERSION="1.3.1"+  cpp-options: -DVERSION="1.4"   build-depends:       base >=4.8 && <5     , base-compat >=0.8.1-    , ansi-terminal >= 0.6.2.3 && < 0.7+    , ansi-terminal >= 0.6.2.3 && < 0.8     , directory     , file-embed >=0.0.10 && <0.1     , filepath     , here     , pretty-show >=1.6.4     , process+    , shakespeare >=2.0.2.2 && <2.1     , temporary     , tabular >=0.2 && <0.3-    , hledger-lib >= 1.3.1+    , time >=1.5+    , utility-ht >= 0.0.13+    , hledger-lib >= 1.4 && < 1.5     , hledger     , bytestring     , containers@@ -264,23 +243,6 @@     , wizards ==1.0.*     , test-framework     , test-framework-hunit-  if impl(ghc <7.6)-    build-depends:-        ghc-prim-  if impl(ghc >=7.10)-    build-depends:-        shakespeare >=2.0.2.2 && <2.1-  else-    build-depends:-        shakespeare >=1.0 && <2.1-      , shakespeare-text >=1.0 && <1.2-  if flag(oldtime)-    build-depends:-        time <1.5-      , old-locale-  else-    build-depends:-        time >=1.5   if (!(os(windows))) && (flag(terminfo))     build-depends:         terminfo@@ -295,25 +257,24 @@   build-depends:       base >=4.8 && <5     , base-compat >=0.8.1-    , ansi-terminal >= 0.6.2.3 && < 0.7+    , ansi-terminal >= 0.6.2.3 && < 0.8     , directory     , file-embed >=0.0.10 && <0.1     , filepath     , here     , pretty-show >=1.6.4     , process+    , shakespeare >=2.0.2.2 && <2.1     , temporary     , tabular >=0.2 && <0.3-    , hledger-lib >= 1.3.1+    , time >=1.5+    , utility-ht >= 0.0.13+    , hledger-lib >= 1.4 && < 1.5     , hledger     , criterion     , html     , timeit-  if flag(oldtime)-    build-depends:-        time <1.5-      , old-locale-  else+  if (!(os(windows))) && (flag(terminfo))     build-depends:-        time >=1.5+        terminfo   default-language: Haskell2010