diff --git a/hledger-lib/Hledger/Query.hs b/hledger-lib/Hledger/Query.hs index 1a6ebd3a7..ae37d253f 100644 --- a/hledger-lib/Hledger/Query.hs +++ b/hledger-lib/Hledger/Query.hs @@ -29,20 +29,21 @@ module Hledger.Query ( matchesQuery, -- * predicates queryIsNull, - queryIsAcct, - queryIsAmt, - queryIsDepth, queryIsDate, queryIsDate2, queryIsDateOrDate2, - queryIsStartDateOnly, - queryIsSym, - queryIsReal, queryIsStatus, - queryIsType, + queryIsCode, + queryIsDesc, queryIsTag, - queryIsAccountRelated, - queryIsTransactionOrPostingRelated, + queryIsAcct, + queryIsType, + queryIsDepth, + queryIsReal, + queryIsAmt, + queryIsSym, + queryIsStartDateOnly, + queryIsTransactionRelated, -- * accessors queryStartDate, queryEndDate, @@ -478,13 +479,9 @@ queryIsNull (And []) = True queryIsNull (Not (Or [])) = True queryIsNull _ = False --- | Is this a simple query of this type ("depth:D") ? --- Note, does not match a compound query like "not:depth:D" or "depth:D acct:A". +-- | Is this a simple query of this type (date:) ? +-- Does not match a compound query involving and/or/not. -- Likewise for the following functions. -queryIsDepth :: Query -> Bool -queryIsDepth (Depth _) = True -queryIsDepth _ = False - queryIsDate :: Query -> Bool queryIsDate (Date _) = True queryIsDate _ = False @@ -498,14 +495,38 @@ queryIsDateOrDate2 (Date _) = True queryIsDateOrDate2 (Date2 _) = True queryIsDateOrDate2 _ = False +queryIsStatus :: Query -> Bool +queryIsStatus (StatusQ _) = True +queryIsStatus _ = False + +queryIsCode :: Query -> Bool +queryIsCode (Code _) = True +queryIsCode _ = False + queryIsDesc :: Query -> Bool queryIsDesc (Desc _) = True queryIsDesc _ = False +queryIsTag :: Query -> Bool +queryIsTag (Tag _ _) = True +queryIsTag _ = False + queryIsAcct :: Query -> Bool queryIsAcct (Acct _) = True queryIsAcct _ = False +queryIsType :: Query -> Bool +queryIsType (Type _) = True +queryIsType _ = False + +queryIsDepth :: Query -> Bool +queryIsDepth (Depth _) = True +queryIsDepth _ = False + +queryIsReal :: Query -> Bool +queryIsReal (Real _) = True +queryIsReal _ = False + queryIsAmt :: Query -> Bool queryIsAmt (Amt _ _) = True queryIsAmt _ = False @@ -514,22 +535,6 @@ queryIsSym :: Query -> Bool queryIsSym (Sym _) = True queryIsSym _ = False -queryIsReal :: Query -> Bool -queryIsReal (Real _) = True -queryIsReal _ = False - -queryIsStatus :: Query -> Bool -queryIsStatus (StatusQ _) = True -queryIsStatus _ = False - -queryIsType :: Query -> Bool -queryIsType (Type _) = True -queryIsType _ = False - -queryIsTag :: Query -> Bool -queryIsTag (Tag _ _) = True -queryIsTag _ = False - -- | Does this query specify a start date and nothing else (that would -- filter postings prior to the date) ? -- When the flag is true, look for a starting secondary date instead. @@ -542,29 +547,18 @@ queryIsStartDateOnly False (Date (DateSpan (Just _) _)) = True queryIsStartDateOnly True (Date2 (DateSpan (Just _) _)) = True queryIsStartDateOnly _ _ = False --- | Does this query involve a property which only accounts (without their balances) have, --- making it inappropriate for matching other things ? -queryIsAccountRelated :: Query -> Bool -queryIsAccountRelated = matchesQuery ( - queryIsAcct - ||| queryIsDepth - ||| queryIsType - ) - --- | Does this query involve a property which only transactions or postings have, --- making it inappropriate for matching other things ? -queryIsTransactionOrPostingRelated :: Query -> Bool -queryIsTransactionOrPostingRelated = matchesQuery ( - queryIsAmt - -- ||| queryIsCode - -- ||| queryIsCur - ||| queryIsDesc - ||| queryIsDate +-- | Does this query involve a property of transactions (or their postings), +-- making it inapplicable to account declarations ? +queryIsTransactionRelated :: Query -> Bool +queryIsTransactionRelated = matchesQuery ( + queryIsDate ||| queryIsDate2 - -- ||| queryIsNote - -- ||| queryIsPayee - ||| queryIsReal ||| queryIsStatus + ||| queryIsCode + ||| queryIsDesc + ||| queryIsReal + ||| queryIsAmt + ||| queryIsSym ) (|||) :: (a->Bool) -> (a->Bool) -> (a->Bool) diff --git a/hledger/Hledger/Cli/Commands/Tags.hs b/hledger/Hledger/Cli/Commands/Tags.hs index b61f72a5f..8277f21d0 100755 --- a/hledger/Hledger/Cli/Commands/Tags.hs +++ b/hledger/Hledger/Cli/Commands/Tags.hs @@ -29,21 +29,28 @@ tags :: CliOpts -> Journal -> IO () tags CliOpts{rawopts_=rawopts,reportspec_=rspec} j = do let today = _rsDay rspec args = listofstringopt "args" rawopts + -- first argument is a tag name pattern, others are a hledger query: hledger tags [TAGREGEX [QUERYARGS..]] mtagpat <- mapM (either Fail.fail pure . toRegexCI . T.pack) $ headMay args let - querystring = map T.pack $ drop 1 args - values = boolopt "values" rawopts - parsed = boolopt "parsed" rawopts - empty = empty_ $ _rsReportOpts rspec - - argsquery <- either usageError (return . fst) $ parseQueryList today querystring + querystr = map T.pack $ drop 1 args + values = boolopt "values" rawopts + parsed = boolopt "parsed" rawopts + empty = empty_ $ _rsReportOpts rspec + query <- either usageError (return . fst) $ parseQueryList today querystr let - q = simplifyQuery $ And [queryFromFlags $ _rsReportOpts rspec, argsquery] - txns = filter (q `matchesTransaction`) $ jtxns $ journalApplyValuationFromOpts rspec j + q = simplifyQuery $ And [queryFromFlags $ _rsReportOpts rspec, query] + matchedtxns = filter (q `matchesTransaction`) $ jtxns $ journalApplyValuationFromOpts rspec j + -- also list tags from matched account declarations, but not if there is + -- a query for something transaction-related, like date: or amt:. + matchedaccts = dbg4 "accts" $ + if dbg4 "queryIsTransactionRelated" $ queryIsTransactionRelated $ dbg4 "q" q + then [] + else filter (matchesAccountExtra (journalAccountType j) (journalInheritedAccountTags j) q) $ + map fst $ jdeclaredaccounts j tagsorvalues = (if parsed then id else nubSort) [ r - | (t,v) <- concatMap transactionAllTags txns + | (t,v) <- concatMap (journalAccountTags j) matchedaccts ++ concatMap transactionAllTags matchedtxns , maybe True (`regexMatchText` t) mtagpat , let r = if values then v else t , not (values && T.null v && not empty) diff --git a/hledger/Hledger/Cli/Commands/Tags.md b/hledger/Hledger/Cli/Commands/Tags.md index 1ce5c9584..b517b8b49 100644 --- a/hledger/Hledger/Cli/Commands/Tags.md +++ b/hledger/Hledger/Cli/Commands/Tags.md @@ -1,14 +1,23 @@ tags\ -List the unique tag names used in the journal. With a TAGREGEX argument, -only tag names matching the regular expression (case insensitive) are shown. -With QUERY arguments, only transactions matching the query are considered. +List the unique tag names used in the journal, whether on transactions, postings, +or account declarations. -With the --values flag, the tags' unique values are listed instead. +With a TAGREGEX argument, only tag names matching this regular expression +(case insensitive, infix matched) are shown. -With --parsed flag, all tags or values are shown in the order they -are parsed from the input data, including duplicates. +With QUERY arguments, only transactions and accounts matching this query are considered. +If the query involves transaction fields (date:, desc:, amt:, ...), +the search is restricted to the matched transactions and their accounts. -With -E/--empty, any blank/empty values will also be shown, otherwise -they are omitted. +With the --values flag, the tags' unique non-empty values are listed instead. +With -E/--empty, blank/empty values are also shown. + +With --parsed, tags or values are shown in the order they were parsed, with duplicates included. +(Except, tags from account declarations are always shown first.) _FLAGS + +Tip: remember, +accounts also acquire tags from their parents, +postings also acquire tags from their account and transaction, +transactions also acquire tags from their postings. diff --git a/hledger/test/tags.test b/hledger/test/tags.test index c328a0699..c7493c492 100644 --- a/hledger/test/tags.test +++ b/hledger/test/tags.test @@ -1,32 +1,56 @@ # tags command -account a ; t1:v1 +account a ; t1:v1, an account tag +account b:bb ; t2:v2, an unused account, depth 2 -2000/1/1 ; t2:v2 - (b) 1 ; t3:v3 +2000/1/1 ; t3:v3, a transaction tag + (a:aa) 1 ; t4:v4, a posting tag -2000/1/2 ; t4:v4 - (b) 1 ; t5:v5 +2000/1/2 ; t5:v4, a reused value + (c) 1 ; t6:v6, an undeclared account -# 1. list all tags -$ hledger -f - tags +# 1. show all tags +$ hledger -f- tags +t1 t2 t3 t4 t5 +t6 -# 2. list tag names matching a regex -$ hledger -f - tags '[24]' -t2 -t4 - -# 3. list tag values -$ hledger -f - tags --values +# 2. show all tag values +$ hledger -f- tags --values +v1 v2 v3 v4 -v5 +v6 -# 4. list values of tags matching a regex from transactions matching a query -$ hledger -f - tags t3 date:2000/1/1 --values -v3 +# 3. show tags matching a regex +$ hledger -f- tags '[1-4]' +t1 +t2 +t3 +t4 + +# 4. show tags matching (a regex and) a hledger query. +# If the query is applicable to both transactions and account declarations, +# both are searched for tags. +$ hledger -f- tags . b c +t2 +t5 +t6 + +# 5. If the query involves transaction attributes, +# only accounts used by the matched transactions will contribute tags. +$ hledger -f- tags . date:2000/1/1 +t1 +t3 +t4 + +# 6. show account tags even when there are no transactions (#1857) +< +account a ; t1: + +$ hledger -f- tags +t1