branch: elpa/beancount
commit 8091f35803ae74de5afb1d12f1b4089348e748b0
Author: Stefan Monnier <monn...@iro.umontreal.ca>
Commit: Stefan Monnier <monn...@iro.umontreal.ca>

    beancount.el: Add beancount-electric-currency
    
    This variable controls the behavior of RET. When non-nil, RET at the
    end of a posting tries to add the currency to the amount, if
    missing. All ways in which an amount can be specified are not
    recognized yet, and the lookup for the account currenclyu can be
    expensive in large ledger files. Thus do not enable this facility by
    default.
---
 beancount-tests.el | 16 ++++++++++++++++
 beancount.el       | 35 +++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+)

diff --git a/beancount-tests.el b/beancount-tests.el
index f0dc935db8..0776df2d2e 100644
--- a/beancount-tests.el
+++ b/beancount-tests.el
@@ -233,3 +233,19 @@ known option nmaes."
                    '("* A"   org-level-1
                      "** B"  org-level-2
                      "*** C" org-level-3)))))
+
+(ert-deftest beancount/account-currency-001 ()
+  :tags '(regress)
+  (with-temp-buffer
+    (insert "
+2019-12-22 open Assets:Test:One USD
+2019-12-22 open Assets:Test:Two USD,EUR
+2019-12-22 open Assets:Test:Three USD \"STRICT\"
+2019-12-22 open Assets:Test:Four USD,EUR \"STRICT\"
+2019-12-22 open Assets:Test:Five \"STRICT\"
+")
+    (should (equal (beancount--account-currency "Assets:Test:One") "USD"))
+    (should (equal (beancount--account-currency "Assets:Test:Two") nil))
+    (should (equal (beancount--account-currency "Assets:Test:Three") "USD"))
+    (should (equal (beancount--account-currency "Assets:Test:Four") nil))
+    (should (equal (beancount--account-currency "Assets:Test:Five") nil))))
diff --git a/beancount.el b/beancount.el
index 4a9a53c477..42d08068b2 100644
--- a/beancount.el
+++ b/beancount.el
@@ -56,6 +56,12 @@ to align all amounts."
   "If non-nil, use ido-style completion rather than the standard."
   :type 'boolean)
 
+(defcustom beancount-electric-currency nil
+  "If non-nil, make `newline' try to add missing currency to
+complete the posting at point. The correct currency is determined
+from the open directive for the relevant account."
+  :type 'boolean)
+
 (defgroup beancount-faces nil "Beancount mode highlighting" :group 'beancount)
 
 (defface beancount-directive
@@ -312,6 +318,7 @@ to align all amounts."
   
   (add-hook 'completion-at-point-functions #'beancount-completion-at-point nil 
t)
   (add-hook 'post-command-hook #'beancount-highlight-transaction-at-point nil 
t)
+  (add-hook 'post-self-insert-hook #'beancount--electric-currency nil t)
   
   (setq-local font-lock-defaults '(beancount-font-lock-keywords))
   (setq-local font-lock-syntax-table t)
@@ -736,6 +743,34 @@ what that column is and returns it (an integer)."
         ))
     column))
 
+(defun beancount--account-currency (account)
+  ;; Build a regexp that matches an open directive that specifies a
+  ;; single account currencydaaee. The currency is match group 1.
+  (let ((re (concat "^" beancount-date-regexp " +open"
+                    "\\s-+" (regexp-quote account)
+                    "\\s-+\\(" beancount-currency-regexp "\\)\\s-+")))
+    (save-excursion
+      (goto-char (point-min))
+      (when (re-search-forward re nil t)
+        ;; The account has declared a single currency, so we can fill it in.
+        (match-string-no-properties 1)))))
+
+(defun beancount--electric-currency ()
+  (when (and beancount-electric-currency (eq last-command-event ?\n))
+    (save-excursion
+      (forward-line -1)
+      (when (and (beancount-inside-transaction-p)
+                 (looking-at (concat "\\s-+\\(" beancount-account-regexp "\\)"
+                                     "\\s-+\\(" beancount-number-regexp 
"\\)\\s-*$")))
+        ;; Last line is a posting without currency.
+        (let* ((account (match-string 1))
+               (pos (match-end 0))
+               (currency (beancount--account-currency account)))
+          (when currency
+            (save-excursion
+             (goto-char pos)
+              (insert " " currency))))))))
+
 (defun beancount-insert-date ()
   "Start a new timestamped directive."
   (interactive)

Reply via email to