match tag names with a regexp, like everything else
This commit is contained in:
parent
92aaeb1109
commit
fdc507bd13
@ -482,10 +482,6 @@ Tags are like Ledger's
|
|||||||
[metadata](http://ledger-cli.org/3.0/doc/ledger3.html#Metadata)
|
[metadata](http://ledger-cli.org/3.0/doc/ledger3.html#Metadata)
|
||||||
feature, except hledger's tag values are always simple strings.
|
feature, except hledger's tag values are always simple strings.
|
||||||
|
|
||||||
Note: when searching with a `tag:` query, currently tag names must
|
|
||||||
match exactly (and case sensitively!). (Tag values are matched in the more
|
|
||||||
usual way, as case-insensitive infix [regular expressions](#regular-expressions)).
|
|
||||||
|
|
||||||
#### Directives
|
#### Directives
|
||||||
|
|
||||||
##### Account aliases
|
##### Account aliases
|
||||||
@ -1014,7 +1010,9 @@ A query term can be any of the following:
|
|||||||
- `desc:REGEX` - match transaction descriptions
|
- `desc:REGEX` - match transaction descriptions
|
||||||
- `date:PERIODEXPR` - match dates within the specified [period](#period-expressions). *Actually, full period syntax is [not yet supported](https://github.com/simonmichael/hledger/issues/141).*
|
- `date:PERIODEXPR` - match dates within the specified [period](#period-expressions). *Actually, full period syntax is [not yet supported](https://github.com/simonmichael/hledger/issues/141).*
|
||||||
- `date2:PERIODEXPR` - as above, but match secondary dates
|
- `date2:PERIODEXPR` - as above, but match secondary dates
|
||||||
- `tag:NAME[=REGEX]` - match by (exact, case sensitive) [tag](#tags) name, and optionally match the tag value by regular expression. Note `tag:` will match a transaction if it or any its postings have the tag, and will match a posting if it or its parent transaction has the tag.
|
- `tag:REGEX[=REGEX]` - match by [tag](#tags) 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 all of their parent transaction's tags.
|
||||||
- `depth:N` - match (or display, depending on command) accounts at or above this [depth](#depth-limiting)
|
- `depth:N` - match (or display, depending on command) accounts at or above this [depth](#depth-limiting)
|
||||||
- `status:*` or `status:!` or `status:` - match cleared, pending, or uncleared/pending transactions respectively
|
- `status:*` or `status:!` or `status:` - match cleared, pending, or uncleared/pending transactions respectively
|
||||||
- `real:1` or `real:0` - match real/virtual-ness
|
- `real:1` or `real:0` - match real/virtual-ness
|
||||||
|
|||||||
@ -47,7 +47,7 @@ import Data.Either
|
|||||||
import Data.List
|
import Data.List
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
import Data.Time.Calendar
|
import Data.Time.Calendar
|
||||||
import Safe (readDef, headDef, headMay)
|
import Safe (readDef, headDef)
|
||||||
import Test.HUnit
|
import Test.HUnit
|
||||||
-- import Text.ParserCombinators.Parsec
|
-- import Text.ParserCombinators.Parsec
|
||||||
import Text.Parsec hiding (Empty)
|
import Text.Parsec hiding (Empty)
|
||||||
@ -68,19 +68,19 @@ data Query = Any -- ^ always match
|
|||||||
| Not Query -- ^ negate this match
|
| Not Query -- ^ negate this match
|
||||||
| Or [Query] -- ^ match if any of these match
|
| Or [Query] -- ^ match if any of these match
|
||||||
| And [Query] -- ^ match if all of these match
|
| And [Query] -- ^ match if all of these match
|
||||||
| Code String -- ^ match if code matches this regexp
|
| Code Regexp -- ^ match if code matches this regexp
|
||||||
| Desc String -- ^ match if description matches this regexp
|
| Desc Regexp -- ^ match if description matches this regexp
|
||||||
| Acct String -- ^ match postings whose account matches this regexp
|
| Acct Regexp -- ^ match postings whose account matches this regexp
|
||||||
| Date DateSpan -- ^ match if primary date in this date span
|
| Date DateSpan -- ^ match if primary date in this date span
|
||||||
| Date2 DateSpan -- ^ match if secondary date in this date span
|
| Date2 DateSpan -- ^ match if secondary date in this date span
|
||||||
| Status ClearedStatus -- ^ match txns/postings with this cleared status (Status Uncleared matches all states except cleared)
|
| Status ClearedStatus -- ^ match txns/postings with this cleared status (Status Uncleared matches all states except cleared)
|
||||||
| Real Bool -- ^ match if "realness" (involves a real non-virtual account ?) has this value
|
| Real Bool -- ^ match if "realness" (involves a real non-virtual account ?) has this value
|
||||||
| Amt OrdPlus Quantity -- ^ match if the amount's numeric quantity is less than/greater than/equal to/unsignedly equal to some value
|
| Amt OrdPlus Quantity -- ^ match if the amount's numeric quantity is less than/greater than/equal to/unsignedly equal to some value
|
||||||
| Sym String -- ^ match if the entire commodity symbol is matched by this regexp
|
| Sym Regexp -- ^ match if the entire commodity symbol is matched by this regexp
|
||||||
| Empty Bool -- ^ if true, show zero-amount postings/accounts which are usually not shown
|
| Empty Bool -- ^ if true, show zero-amount postings/accounts which are usually not shown
|
||||||
-- more of a query option than a query criteria ?
|
-- more of a query option than a query criteria ?
|
||||||
| Depth Int -- ^ match if account depth is less than or equal to this value
|
| Depth Int -- ^ match if account depth is less than or equal to this value
|
||||||
| Tag String (Maybe String) -- ^ match if a tag with this exact name, and with value
|
| Tag Regexp (Maybe Regexp) -- ^ match if a tag's name, and optionally its value, is matched by these respective regexps
|
||||||
-- matching the regexp if provided, exists
|
-- matching the regexp if provided, exists
|
||||||
deriving (Eq,Data,Typeable)
|
deriving (Eq,Data,Typeable)
|
||||||
|
|
||||||
@ -330,7 +330,7 @@ tests_parseAmountQueryTerm = [
|
|||||||
"-0.23" `gives` (Eq,(-0.23))
|
"-0.23" `gives` (Eq,(-0.23))
|
||||||
]
|
]
|
||||||
|
|
||||||
parseTag :: String -> (String, Maybe String)
|
parseTag :: String -> (Regexp, Maybe Regexp)
|
||||||
parseTag s | '=' `elem` s = (n, Just $ tail v)
|
parseTag s | '=' `elem` s = (n, Just $ tail v)
|
||||||
| otherwise = (s, Nothing)
|
| otherwise = (s, Nothing)
|
||||||
where (n,v) = break (=='=') s
|
where (n,v) = break (=='=') s
|
||||||
@ -660,8 +660,7 @@ matchesPosting q@(Amt _ _) Posting{pamount=amt} = q `matchesMixedAmount` amt
|
|||||||
-- matchesPosting (Empty True) Posting{pamount=a} = isZeroMixedAmount a
|
-- matchesPosting (Empty True) Posting{pamount=a} = isZeroMixedAmount a
|
||||||
matchesPosting (Empty _) _ = True
|
matchesPosting (Empty _) _ = True
|
||||||
matchesPosting (Sym r) Posting{pamount=Mixed as} = any (regexMatchesCI $ "^" ++ r ++ "$") $ map acommodity as
|
matchesPosting (Sym r) Posting{pamount=Mixed as} = any (regexMatchesCI $ "^" ++ r ++ "$") $ map acommodity as
|
||||||
matchesPosting (Tag n Nothing) p = isJust $ lookupTagByName n $ postingAllTags p
|
matchesPosting (Tag n v) p = not $ null $ matchedTags n v $ postingAllTags p
|
||||||
matchesPosting (Tag n (Just v)) p = isJust $ lookupTagByNameAndValue (n,v) $ postingAllTags p
|
|
||||||
-- matchesPosting _ _ = False
|
-- matchesPosting _ _ = False
|
||||||
|
|
||||||
tests_matchesPosting = [
|
tests_matchesPosting = [
|
||||||
@ -715,8 +714,7 @@ matchesTransaction q@(Amt _ _) t = any (q `matchesPosting`) $ tpostings t
|
|||||||
matchesTransaction (Empty _) _ = True
|
matchesTransaction (Empty _) _ = True
|
||||||
matchesTransaction (Depth d) t = any (Depth d `matchesPosting`) $ tpostings t
|
matchesTransaction (Depth d) t = any (Depth d `matchesPosting`) $ tpostings t
|
||||||
matchesTransaction q@(Sym _) t = any (q `matchesPosting`) $ tpostings t
|
matchesTransaction q@(Sym _) t = any (q `matchesPosting`) $ tpostings t
|
||||||
matchesTransaction (Tag n Nothing) t = isJust $ lookupTagByName n $ transactionAllTags t
|
matchesTransaction (Tag n v) t = not $ null $ matchedTags n v $ transactionAllTags t
|
||||||
matchesTransaction (Tag n (Just v)) t = isJust $ lookupTagByNameAndValue (n,v) $ transactionAllTags t
|
|
||||||
|
|
||||||
-- matchesTransaction _ _ = False
|
-- matchesTransaction _ _ = False
|
||||||
|
|
||||||
@ -732,17 +730,13 @@ tests_matchesTransaction = [
|
|||||||
assertBool "" $ (Tag "postingtag" Nothing) `matchesTransaction` nulltransaction{tpostings=[nullposting{ptags=[("postingtag","")]}]}
|
assertBool "" $ (Tag "postingtag" Nothing) `matchesTransaction` nulltransaction{tpostings=[nullposting{ptags=[("postingtag","")]}]}
|
||||||
]
|
]
|
||||||
|
|
||||||
lookupTagByName :: String -> [Tag] -> Maybe Tag
|
-- | Filter a list of tags by matching against their names and
|
||||||
lookupTagByName namepat tags = headMay [(n,v) | (n,v) <- tags, matchTagName namepat n]
|
-- optionally also their values.
|
||||||
|
matchedTags :: Regexp -> Maybe Regexp -> [Tag] -> [Tag]
|
||||||
lookupTagByNameAndValue :: Tag -> [Tag] -> Maybe Tag
|
matchedTags namepat valuepat tags = filter (match namepat valuepat) tags
|
||||||
lookupTagByNameAndValue (namepat, valpat) tags = headMay [(n,v) | (n,v) <- tags, matchTagName namepat n, matchTagValue valpat v]
|
where
|
||||||
|
match npat Nothing (n,_) = regexMatchesCI npat n
|
||||||
matchTagName :: String -> String -> Bool
|
match npat (Just vpat) (n,v) = regexMatchesCI npat n && regexMatchesCI vpat v
|
||||||
matchTagName pat name = pat == name
|
|
||||||
|
|
||||||
matchTagValue :: String -> String -> Bool
|
|
||||||
matchTagValue pat value = regexMatchesCI pat value
|
|
||||||
|
|
||||||
-- tests
|
-- tests
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user