diff --git a/hledger-lib/Hledger/Data/AccountName.hs b/hledger-lib/Hledger/Data/AccountName.hs index 8d157bb4a..3d0663cc6 100644 --- a/hledger-lib/Hledger/Data/AccountName.hs +++ b/hledger-lib/Hledger/Data/AccountName.hs @@ -376,5 +376,21 @@ tests_AccountName = testGroup "AccountName" [ accountNameInferType "revenues" @?= Just Revenue accountNameInferType "revenue" @?= Just Revenue accountNameInferType "income" @?= Just Revenue + ,testCase "joinAccountNames" $ do + joinAccountNames "assets" "cash" @?= "assets:cash" + joinAccountNames "assets:cash" "a" @?= "assets:cash:a" + joinAccountNames "assets" "(cash)" @?= "(assets:cash)" + joinAccountNames "assets" "[cash]" @?= "[assets:cash]" + joinAccountNames "(assets)" "cash" @?= "(assets:cash)" + joinAccountNames "" "assets" @?= "assets" + joinAccountNames "assets" "" @?= "assets" + ,testCase "concatAccountNames" $ do + concatAccountNames ["assets", "cash"] @?= "assets:cash" + concatAccountNames ["assets:cash", "a"] @?= "assets:cash:a" + concatAccountNames ["assets", "(cash)"] @?= "(assets:cash)" + concatAccountNames ["assets", "[cash]"] @?= "[assets:cash]" + concatAccountNames ["(assets)", "cash"] @?= "(assets:cash)" + concatAccountNames ["", "assets"] @?= ":assets" + concatAccountNames ["assets", ""] @?= "assets:" ] diff --git a/hledger-lib/Hledger/Read/JournalReader.hs b/hledger-lib/Hledger/Read/JournalReader.hs index b55dc7178..753f66969 100644 --- a/hledger-lib/Hledger/Read/JournalReader.hs +++ b/hledger-lib/Hledger/Read/JournalReader.hs @@ -433,7 +433,7 @@ addAccountDeclaration (a,cmt,tags,pos) = do modify' (\j -> let decls = jdeclaredaccounts j - d = (a, nullaccountdeclarationinfo{ + d = (textUnbracket a, nullaccountdeclarationinfo{ adicomment = cmt ,aditags = tags ,adideclarationorder = length decls + 1 -- gets renumbered when Journals are finalised or merged diff --git a/hledger-lib/Hledger/Utils/Text.hs b/hledger-lib/Hledger/Utils/Text.hs index a91f5433f..aad96d013 100644 --- a/hledger-lib/Hledger/Utils/Text.hs +++ b/hledger-lib/Hledger/Utils/Text.hs @@ -53,6 +53,7 @@ where import Data.Char (digitToInt) import Data.Default (def) +import Data.Maybe (catMaybes) import Data.Text (Text) import qualified Data.Text as T import qualified Data.Text.Lazy as TL @@ -175,12 +176,17 @@ isDoubleQuoted :: Text -> Bool isDoubleQuoted s = T.length s >= 2 && T.head s == '"' && T.last s == '"' +-- | Remove all matching pairs of square brackets and parentheses from the text. textUnbracket :: Text -> Text -textUnbracket s - | T.null s = s - | T.head s == '[' && T.last s == ']' = T.init $ T.tail s - | T.head s == '(' && T.last s == ')' = T.init $ T.tail s - | otherwise = s +textUnbracket s = T.drop stripN $ T.dropEnd stripN s + where + matchBracket :: Char -> Maybe Char + matchBracket '(' = Just ')' + matchBracket '[' = Just ']' + matchBracket _ = Nothing + + expectedClosingBrackets = catMaybes $ takeWhile (/= Nothing) $ matchBracket <$> T.unpack s + stripN = length $ takeWhile (uncurry (==)) $ zip expectedClosingBrackets $ reverse $ T.unpack s -- | Join several multi-line strings as side-by-side rectangular strings of the same height, top-padded. -- Treats wide characters as double width. @@ -271,5 +277,18 @@ tests_Text = testGroup "Text" [ quoteIfSpaced "mimi's cafe" @?= "\"mimi's cafe\"" quoteIfSpaced "\"alex\" cafe" @?= "\"\\\"alex\\\" cafe\"" quoteIfSpaced "le'shan's cafe" @?= "\"le'shan's cafe\"" - quoteIfSpaced "\"be'any's\" cafe" @?= "\"\\\"be'any's\\\" cafe\"" + quoteIfSpaced "\"be'any's\" cafe" @?= "\"\\\"be'any's\\\" cafe\"", + testCase "textUnbracket" $ do + textUnbracket "()" @?= "" + textUnbracket "(a)" @?= "a" + textUnbracket "(ab)" @?= "ab" + textUnbracket "[ab]" @?= "ab" + textUnbracket "([ab])" @?= "ab" + textUnbracket "(()b)" @?= "()b" + textUnbracket "[[]b]" @?= "[]b" + textUnbracket "[()b]" @?= "()b" + textUnbracket "[([]())]" @?= "[]()" + textUnbracket "[([[[()]]])]" @?= "" + textUnbracket "[([[[(]]])]" @?= "(" + textUnbracket "[([[[)]]])]" @?= ")" ] diff --git a/hledger/hledger.m4.md b/hledger/hledger.m4.md index 899f3cc60..56e8e4d11 100644 --- a/hledger/hledger.m4.md +++ b/hledger/hledger.m4.md @@ -1769,6 +1769,12 @@ They are written as the word `account` followed by a hledger-style [account name account assets:bank:checking ``` +Note, however, that account names declared in the account directive are stripped of surrounding brackets and parentheses. +The above directive is thus equivalent to this: +```journal +account (assets:bank:checking) +``` + ### Account comments Text following **two or more spaces** and `;` at the end of an account directive line, diff --git a/hledger/test/journal/directive-account.test b/hledger/test/journal/directive-account.test index 154a5e3aa..94abceaeb 100644 --- a/hledger/test/journal/directive-account.test +++ b/hledger/test/journal/directive-account.test @@ -68,6 +68,29 @@ account Expenses:Food $ hledger -f- accounts Expenses:Food +# 5. It unbrackets account names. +< +account (a) +account (a:aa) +account (a:(aaa)) +account [b] +account [b:bb] +account [b:[bbb]] +account [([c])] +account [([c:cc])] +account [([c:[ccc]])] + +$ hledger -f- accounts +a +a:aa +a:(aaa) +b +b:bb +b:[bbb] +c +c:cc +c:[ccc] + # TODO # a trailing : should give a clear error # 2009/1/1 diff --git a/hledger/test/journal/parens-in-account-name.test b/hledger/test/journal/parens-in-account-name.test index 7480123da..b41a6ad7c 100644 --- a/hledger/test/journal/parens-in-account-name.test +++ b/hledger/test/journal/parens-in-account-name.test @@ -1,9 +1,13 @@ +# Tests for parentheses and brackets in account names + +# 1. Parentheses in the middle of an account name are ignored. hledger -f - print <<< 2009-01-01 x a 2 b (b) b -1 c + >>> 2009-01-01 x a 2 @@ -11,3 +15,19 @@ hledger -f - print c >>>=0 + +# 2. Nested parentheses are removed and the outer brackets are used as the type. +hledger -f- print +<<< +2023-01-01 + [([(a)])] 1 + [(b:bb)] 1 + [b:[bbb]] + +>>> +2023-01-01 + [a] 1 + [b:bb] 1 + [b:[bbb]] + +>>>=0