branch: elpa/beancount commit ba6bada870eb33f9444a9e39a1eedd420cd870d4 Author: Daniele Nicolodi <dani...@grinta.net> Commit: Daniele Nicolodi <dani...@grinta.net>
beancount.el: Rework imenu support and add tests In org-mode the imemu entries are organized in a tree, however this only allows to jump to leaf nodes, with no possibility to select intermediate nodes. To avoid this problem, follow what outline-mode does and organize the imenu entries in a flat structure. To make it easier to select the entries in the minibuffer, the outline indicators are removed from the node labels. --- beancount-tests.el | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ beancount.el | 32 ++++---------------------------- 2 files changed, 58 insertions(+), 28 deletions(-) diff --git a/beancount-tests.el b/beancount-tests.el index 0776df2d2e..7dc15e0c31 100644 --- a/beancount-tests.el +++ b/beancount-tests.el @@ -249,3 +249,57 @@ known option nmaes." (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)))) + +(ert-deftest beancount/imenu-001 () + :tags '(regress imenu) + (with-temp-buffer + (insert " +;;; 2019 +;;;; 2019 January +;;;; 2019 February +;;; 2020 +;;;; 2020 January + +2020-01-01 * \"Example\" + Expenses:Test 1.00 USD + Assets:Checking + +;;;; 2020 February +") + (beancount-mode) + (outline-minor-mode) + (let* ((imenu-use-markers nil) ; makes testing easier + (index (funcall imenu-create-index-function))) + (should (equal index '(("2019" . 2) + ("2019 January" . 11) + ("2019 February" . 29) + ("2020" . 48) + ("2020 January" . 57) + ("2020 February" . 146))))))) + +(ert-deftest beancount/imenu-002 () + :tags '(regress imenu) + (with-temp-buffer + (insert " +* 2019 +** 2019 January + +2019-01-01 * \"Example\" + Expenses:Test 1.00 USD + Assets:Checking + +** 2019 February +* 2020 +** 2020 January +** 2020 February +") + (beancount-mode) + (outline-minor-mode) + (let* ((imenu-use-markers nil) ; makes testing easier + (index (funcall imenu-create-index-function))) + (should (equal index '(("2019" . 2) + ("2019 January" . 9) + ("2019 February" . 96) + ("2020" . 113) + ("2020 January" . 120) + ("2020 February" . 136))))))) diff --git a/beancount.el b/beancount.el index 08fbdde4ea..9ac5c1484d 100644 --- a/beancount.el +++ b/beancount.el @@ -214,6 +214,8 @@ from the open directive for the relevant account." (defconst beancount-metadata-regexp "^\\s-+\\([a-z][A-Za-z0-9_-]+:\\)\\s-+\\(.+\\)") +;; This is a grouping regular expression because the subexpression is +;; used in determining the outline level in `beancount-outline-level'. (defvar beancount-outline-regexp "\\(;;;+\\|\\*+\\)") (defun beancount-outline-level () @@ -326,7 +328,8 @@ from the open directive for the relevant account." (setq-local outline-regexp beancount-outline-regexp) (setq-local outline-level #'beancount-outline-level) - (setq-local imenu-create-index-function #'beancount-imenu-create-index-function)) + (setq imenu-generic-expression + (list (list nil (concat "^" beancount-outline-regexp "\\s-+\\(.*\\)$") 2)))) (defun beancount-collect-pushed-tags (begin end) "Return list of all pushed (and not popped) tags in the region." @@ -1011,32 +1014,5 @@ Essentially a much simplified version of `next-line'." (get-char-property (1- (point)) 'invisible)) (beginning-of-line 2))) -;;; imenu support -(defun beancount-imenu-create-index-function () - "The `imenu-create-index-function' for beancount-mode that returns an -`imenu--index-alist' that stores the headings in the buffer." - (let ((index-alist '())) - (goto-char (point-max)) - (while (re-search-backward "^\\(\\*+\\|;;;+\\)[ \t]+\\(.*?\\)[ \t]*$" nil t) - (let ((level (beancount-outline-level)) - (name (match-string-no-properties 2)) - (pos (point))) - (cond ((not index-alist) - (push (cons level (cons name pos)) index-alist)) - ((< level (caar index-alist)) - (let ((sub-index-alist index-alist)) - (while (and (cdr index-alist) - (< level (caadr index-alist))) - (setcar index-alist (cdar index-alist)) - (pop index-alist)) - (let ((sub-index-tail index-alist)) - (setcar index-alist (cdar index-alist)) - (pop index-alist) - (setcdr sub-index-tail nil)) - (push (cons level (cons name sub-index-alist)) index-alist) - )) - (t (push (cons level (cons name pos)) index-alist))))) - (mapcar 'cdr index-alist))) - (provide 'beancount) ;;; beancount.el ends here