@@ -26,6 +26,7 @@ import qualified Data.Text.Lazy as TL
2626import qualified Data.Text.Lazy.Builder as TB
2727import Safe (maximumBound )
2828import Text.DocLayout (realLength )
29+ import Text.Printf
2930import Text.Tabular.AsciiWide hiding (render )
3031
3132import Hledger.Utils
@@ -109,7 +110,7 @@ postingAsLinesBeancount elideamount acctwidth amtwidth p =
109110 | elideamount = [mempty ]
110111 | otherwise = showMixedAmountLinesB displayopts a'
111112 where
112- displayopts = defaultFmt{ displayZeroCommodity= True , displayForceDecimalMark= True }
113+ displayopts = defaultFmt{ displayZeroCommodity= True , displayForceDecimalMark= True , displayQuotes = False }
113114 a' = mapMixedAmount amountToBeancount $ pamount p
114115 thisamtwidth = maximumBound 0 $ map wbWidth shownAmounts
115116
@@ -137,12 +138,12 @@ type BeancountAccountName = AccountName
137138type BeancountAccountNameComponent = AccountName
138139
139140-- | Convert a hledger account name to a valid Beancount account name.
140- -- It replaces non-supported characters with a dash, it prepends the letter B
141- -- to any part which doesn't begin with a letter or number, and it capitalises each part.
142- -- It's possible this could generate the same beancount name for distinct hledger account names .
141+ -- It replaces spaces with dashes and other non-supported characters with C<HEXBYTES>;
142+ -- prepends the letter A- to any part which doesn't begin with a letter or number;
143+ -- and capitalises each part .
143144-- It also checks that the first part is one of the required english
144145-- account names Assets, Liabilities, Equity, Income, or Expenses, and if not
145- -- it raises an informative error suggesting --alias .
146+ -- raises an informative error.
146147-- Ref: https://beancount.github.io/docs/beancount_language_syntax.html#accounts
147148accountNameToBeancount :: AccountName -> BeancountAccountName
148149accountNameToBeancount a =
@@ -174,16 +175,19 @@ accountNameComponentToBeancount acctpart =
174175 Nothing -> " "
175176 Just (c,cs) ->
176177 textCapitalise $
177- T. map (\ d -> if isBeancountAccountChar d then d else ' - ' ) $ T. cons c cs
178+ T. concatMap (\ d -> if isBeancountAccountChar d then ( T. singleton d) else T. pack $ charToBeancount d ) $ T. cons c cs
178179 where
179180 prependStartCharIfNeeded t =
180181 case T. uncons t of
181182 Just (c,_) | not $ isBeancountAccountStartChar c -> T. cons beancountAccountDummyStartChar t
182183 _ -> t
183184
184- -- | Dummy valid starting character to prepend to Beancount account name parts if needed (B ).
185+ -- | Dummy valid starting character to prepend to Beancount account name parts if needed (A ).
185186beancountAccountDummyStartChar :: Char
186- beancountAccountDummyStartChar = ' B'
187+ beancountAccountDummyStartChar = ' A'
188+
189+ charToBeancount :: Char -> String
190+ charToBeancount c = if isSpace c then " -" else printf " C%x" c
187191
188192-- XXX these probably allow too much unicode:
189193
@@ -222,25 +226,24 @@ type BeancountCommoditySymbol = CommoditySymbol
222226-- That is: 2-24 uppercase letters / digits / apostrophe / period / underscore / dash,
223227-- starting with a letter, and ending with a letter or digit.
224228-- Ref: https://beancount.github.io/docs/beancount_language_syntax.html#commodities-currencies
225- -- So this: removes any enclosing double quotes,
226- -- replaces some common currency symbols with currency codes,
229+ -- So this:
230+ -- replaces common currency symbols with their ISO 4217 currency codes,
227231-- capitalises all letters,
228- -- replaces any invalid characters with a dash (-),
229- -- prepends a B if the first character is not a letter,
230- -- and appends a B if the last character is not a letter or digit.
231- -- It's possible this could generate unreadable commodity names,
232- -- or the same beancount name for distinct hledger commodity names.
232+ -- replaces spaces with dashes and other invalid characters with C<HEXBYTES>,
233+ -- prepends a C if the first character is not a letter,
234+ -- appends a C if the last character is not a letter or digit,
235+ -- and disables hledger's enclosing double quotes.
233236--
234237-- >>> commodityToBeancount ""
235- -- "B "
238+ -- "C "
236239-- >>> commodityToBeancount "$"
237240-- "USD"
238241-- >>> commodityToBeancount "Usd"
239242-- "USD"
240243-- >>> commodityToBeancount "\"a1\""
241244-- "A1"
242245-- >>> commodityToBeancount "\"A 1!\""
243- -- "A-1-B "
246+ -- "A-1C21 "
244247--
245248commodityToBeancount :: CommoditySymbol -> BeancountCommoditySymbol
246249commodityToBeancount com =
@@ -251,16 +254,16 @@ commodityToBeancount com =
251254 Nothing ->
252255 com'
253256 & T. toUpper
254- & T. map (\ d -> if isBeancountCommodityChar d then d else ' - ' )
257+ & T. concatMap (\ d -> if isBeancountCommodityChar d then T. singleton d else T. pack $ charToBeancount d )
255258 & fixstart
256259 & fixend
257260 where
258261 fixstart bcom = case T. uncons bcom of
259262 Just (c,_) | isBeancountCommodityStartChar c -> bcom
260- _ -> " B " <> bcom
263+ _ -> " C " <> bcom
261264 fixend bcom = case T. unsnoc bcom of
262265 Just (_,c) | isBeancountCommodityEndChar c -> bcom
263- _ -> bcom <> " B "
266+ _ -> bcom <> " C "
264267
265268-- | Is this a valid character in the middle of a Beancount commodity name (a capital letter, digit, or '._-) ?
266269isBeancountCommodityChar :: Char -> Bool
0 commit comments