A bunch of account sorting changes that got intermingled.
First, account codes have been dropped. They can still be parsed and
will be ignored, for now. I don't know if anyone used them.
Instead, account display order is now controlled by the order of account
directives, if any. From the mail list:
I'd like to drop account codes, introduced in hledger 1.9 to control
the display order of accounts. In my experience,
- they are tedious to maintain
- they duplicate/compete with the natural tendency to arrange account
directives to match your mental chart of accounts
- they duplicate/compete with the tree structure created by account
names
and it gets worse if you think about using them more extensively,
eg to classify accounts by type.
Instead, I plan to just let the position (parse order) of account
directives determine the display order of those declared accounts.
Undeclared accounts will be displayed after declared accounts,
sorted alphabetically as usual.
Second, the various account sorting modes have been implemented more
widely and more correctly. All sorting modes (alphabetically, by account
declaration, by amount) should now work correctly in almost all commands
and modes (non-tabular and tabular balance reports, tree and flat modes,
the accounts command). Sorting bugs have been fixed, eg #875.
Only the budget report (balance --budget) does not yet support sorting.
Comprehensive functional tests for sorting in the accounts and balance
commands have been added. If you are confused by some sorting behaviour,
studying these tests is recommended, as sorting gets tricky.
102 lines
4.3 KiB
Haskell
102 lines
4.3 KiB
Haskell
{-|
|
|
|
|
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 MultiWayIf #-}
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
{-# LANGUAGE CPP #-}
|
|
|
|
module Hledger.Cli.Commands.Accounts (
|
|
accountsmode
|
|
,accounts
|
|
) where
|
|
|
|
#if !(MIN_VERSION_base(4,11,0))
|
|
import Data.Monoid
|
|
#endif
|
|
import Data.List
|
|
import qualified Data.Text as T
|
|
import qualified Data.Text.IO as T
|
|
import System.Console.CmdArgs.Explicit as C
|
|
|
|
import Hledger
|
|
import Hledger.Cli.CliOptions
|
|
|
|
|
|
-- | Command line options for this command.
|
|
accountsmode = (defCommandMode $ ["accounts"] ++ aliases) {
|
|
modeHelp = "show account names" `withAliases` aliases
|
|
,modeHelpSuffix = [
|
|
"This command lists account names, either declared with account directives"
|
|
,"(--declared), posted to (--used), or both (default)."
|
|
,"With query arguments, only matched account names and account names"
|
|
,"referenced by matched postings are shown."
|
|
,"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 components."
|
|
,"Account names can be depth-clipped with `--depth N` or depth:N."
|
|
]
|
|
,modeGroupFlags = C.Group {
|
|
groupUnnamed = [
|
|
flagNone ["declared"] (\opts -> setboolopt "declared" opts) "show account names declared with account directives"
|
|
,flagNone ["used"] (\opts -> setboolopt "used" opts) "show account names referenced by transactions"
|
|
,flagNone ["codes"] (\opts -> setboolopt "codes" opts) "also show numeric account codes"
|
|
,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{rawopts_=rawopts, reportopts_=ropts} j = do
|
|
|
|
-- 1. identify the accounts we'll show
|
|
d <- getCurrentDay
|
|
let tree = tree_ ropts
|
|
declared = boolopt "declared" rawopts
|
|
used = boolopt "used" rawopts
|
|
q = queryFromOpts d ropts
|
|
-- a depth limit will clip and exclude account names later, but should not exclude accounts at this stage
|
|
nodepthq = dbg1 "nodepthq" $ filterQuery (not . queryIsDepth) q
|
|
depth = dbg1 "depth" $ queryDepth $ filterQuery queryIsDepth q
|
|
matcheddeclaredaccts = dbg1 "matcheddeclaredaccts" $ filter (matchesAccount nodepthq) $ jdeclaredaccounts j
|
|
matchedusedaccts = dbg5 "matchedusedaccts" $ map paccount $ journalPostings $ filterJournalPostings nodepthq j
|
|
accts = dbg5 "accts to show" $ -- no need to nub/sort, accountTree will
|
|
if | declared && not used -> matcheddeclaredaccts
|
|
| not declared && used -> matchedusedaccts
|
|
| otherwise -> matcheddeclaredaccts ++ matchedusedaccts
|
|
|
|
-- 2. sort them by declaration order and name, at each level of their tree structure
|
|
sortedaccts = sortAccountNamesByDeclaration j tree accts
|
|
|
|
-- 3. if there's a depth limit, depth-clip and remove any no longer useful items
|
|
clippedaccts =
|
|
dbg1 "clippedaccts" $
|
|
filter (matchesAccount q) $ -- clipping can leave accounts that no longer visibly match the query
|
|
nub $ -- clipping can leave duplicates (adjacent, hopefully)
|
|
filter (not . T.null) $ -- depth:0 can leave nulls
|
|
map (clipAccountName depth) $ -- clip at depth if specified
|
|
sortedaccts
|
|
|
|
-- 4. print what remains as a list or tree, maybe applying --drop in the former case
|
|
mapM_ (T.putStrLn . render) clippedaccts
|
|
where
|
|
render a
|
|
| tree_ ropts = T.replicate (2 * (accountNameLevel a - 1)) " " <> accountLeafName a
|
|
| otherwise = maybeAccountNameDrop ropts a
|
|
|