From f518f15e64c0ec7e22e6d5980270b201c838c590 Mon Sep 17 00:00:00 2001 From: Juan Wajnerman Date: Mon, 18 May 2026 23:26:49 -0300 Subject: [PATCH] imp: print: beancount: convert underscores in account names to CamelCase Underscore-separated subparts within an account name component are now capitalised and joined, so e.g. assets:wells_fargo:fima_usd becomes Assets:WellsFargo:FimaUsd instead of the previous hex-encoded Assets:WellsC5ffargo:FimaC5fusd. Underscores in hledger account names are conventionally used as a space substitute, so treating them as word boundaries produces much cleaner Beancount output. --- hledger-lib/Hledger/Write/Beancount.hs | 11 +++++------ hledger/hledger.m4.md | 4 +++- hledger/test/print/beancount.test | 4 ++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/hledger-lib/Hledger/Write/Beancount.hs b/hledger-lib/Hledger/Write/Beancount.hs index 5deb9828529..75d9c770e93 100644 --- a/hledger-lib/Hledger/Write/Beancount.hs +++ b/hledger-lib/Hledger/Write/Beancount.hs @@ -256,7 +256,9 @@ type BeancountAccountNameComponent = AccountName -- It replaces spaces with dashes and other non-supported characters with C; -- prepends the letter A to any part which doesn't begin with a letter or number; -- adds a second :A part if there is only one part; --- and capitalises each part. +-- and capitalises each part (also capitalising each underscore-separated +-- subpart within a part and joining them, so e.g. "wells_fargo" becomes +-- "WellsFargo"). -- It also checks that the first part is one of the required english -- account names Assets, Liabilities, Equity, Income, or Expenses, and if not -- raises an informative error. @@ -289,12 +291,9 @@ accountNameToBeancount a = b accountNameComponentToBeancount :: AccountName -> BeancountAccountNameComponent accountNameComponentToBeancount acctpart = prependStartCharIfNeeded $ - case T.uncons acctpart of - Nothing -> "" - Just (c,cs) -> - textCapitalise $ - T.concatMap (\d -> if isBeancountAccountChar d then (T.singleton d) else T.pack $ charToBeancount d) $ T.cons c cs + T.concat $ map (textCapitalise . encodeChars) $ T.split (=='_') acctpart where + encodeChars = T.concatMap (\d -> if isBeancountAccountChar d then T.singleton d else T.pack $ charToBeancount d) prependStartCharIfNeeded t = case T.uncons t of Just (c,_) | not $ isBeancountAccountStartChar c -> T.cons beancountAccountDummyStartChar t diff --git a/hledger/hledger.m4.md b/hledger/hledger.m4.md index f10e7b35e3e..81296c9aff4 100644 --- a/hledger/hledger.m4.md +++ b/hledger/hledger.m4.md @@ -842,7 +842,9 @@ or this [hledger2beancount.conf](https://github.com/simonmichael/hledger/blob/ma Aside from the top-level names, hledger will adjust your account names to make valid [Beancount account names](https://beancount.github.io/docs/beancount_language_syntax.html#accounts), -by capitalising each part, replacing spaces with `-`, replacing other unsupported characters with `C`, +by capitalising each part (also capitalising each underscore-separated subpart and joining them, +so e.g. `wells_fargo` becomes `WellsFargo`), +replacing spaces with `-`, replacing other unsupported characters with `C`, prepending `A` to account name parts which don't begin with a letter or digit, and appending `:A` to account names which have only one part. diff --git a/hledger/test/print/beancount.test b/hledger/test/print/beancount.test index b54b2398c83..8db82ef1fda 100644 --- a/hledger/test/print/beancount.test +++ b/hledger/test/print/beancount.test @@ -10,19 +10,23 @@ $ hledger -f- print -O beancount >=1 # ** 2. Otherwise, accounts are modified/encoded to suit beancount, and open directives are added. +# Underscore-separated subparts within a component are capitalised and joined. < 2000-01-01 assets 0 ABC equity:$-€:$ 0 USD + assets:my_cash 0 ABC $ hledger -f- print -O beancount ;option "inferred_tolerance_default" "*:0.005" 2000-01-01 open Assets:A +2000-01-01 open Assets:MyCash 2000-01-01 open Equity:C24-C20ac:C24 2000-01-01 * Assets:A 0 ABC Equity:C24-C20ac:C24 0 USD + Assets:MyCash 0 ABC >=