doomemacs/modules/lang/beancount/config.el
Henrik Lissner 5fca440beb lang/beancount: add beancount-langserver support
Mentioned in #5035.
Remove when emacs-lsp/lsp-mode#2863 is resolved.
2021-05-11 17:57:21 -04:00

94 lines
3.9 KiB
EmacsLisp

;;; lang/beancount/config.el -*- lexical-binding: t; -*-
(use-package! beancount
:mode ("\\.beancount\\'" . beancount-mode)
:init
(add-hook 'beancount-mode-hook #'outline-minor-mode)
(after! all-the-icons
(add-to-list 'all-the-icons-icon-alist
'("\\.beancount\\'" all-the-icons-material "attach_money" :face all-the-icons-lblue))
(add-to-list 'all-the-icons-mode-icon-alist
'(beancount-mode all-the-icons-material "attach_money" :face all-the-icons-lblue)))
;; TODO PR this upstream
(defadvice! +beancount--fix-faces-a ()
"`beancount-outline-face' returns org-level-N faces for beancount-mode's
font-lock keywords, but there is no guarantee `org' will be loaded when
beancount-mode is activated. If it is absent, you will see a flood of 'invalid
face' errors. Just use the outline-N faces to get around this.
This msut be advised *before* beancount-mode loads, because
`beancount-outline-face' is used at load time."
:override #'beancount-outline-face
(if outline-minor-mode
(let ((level (funcall outline-level)))
(if (integerp level)
(intern (format "outline-%d" level))))
nil))
:config
(when (featurep! +lsp)
(after! lsp-mode
;; TODO PR this upstream
(add-to-list 'lsp-language-id-configuration '(beancount-mode . "beancount"))
(defvar lsp-beancount-langserver-executable "beancount-langserver")
(defvar lsp-beancount-journal-file nil)
(defvar lsp-beancount-python-interpreter
(or (executable-find "python3")
(executable-find "python")))
(lsp-register-client
(make-lsp-client :new-connection
(lsp-stdio-connection `(,lsp-beancount-langserver-executable "--stdio"))
:major-modes '(beancount-mode)
:initialization-options
`((journalFile . ,lsp-beancount-journal-file)
(pythonPath . ,lsp-beancount-python-interpreter))
:server-id 'beancount-ls)))
(add-hook 'beancount-mode-local-vars-hook #'lsp!))
(setq beancount-electric-currency t)
(map! :map beancount-mode-map
"TAB" (cmds! (and outline-minor-mode (outline-on-heading-p))
#'beancount-outline-cycle
#'indent-according-to-mode)
:localleader
"b" #'+beancount/balance
"c" #'beancount-check
"l" #'beancount-linked
"q" #'beancount-query
"x" #'beancount-context
(:prefix ("i" . "insert")
"a" #'beancount-insert-account
"p" #'beancount-insert-prices
"d" #'beancount-insert-date))
;; TODO PR this upstream?
(defun +beancount-electric-align-h ()
"Align amount in current line to `beancount-number-alignment-column'."
(when (and beancount-electric-currency (eq last-command-event ?\n))
(save-excursion
(forward-line -1)
(ignore-errors (beancount-align-to-previous-number)))))
(add-hook! 'beancount-mode-hook
(add-hook 'post-self-insert-hook #'+beancount-electric-align-h 'append t))
;; TODO PR this upstream
(defadvice! +beancount--fix-account-currency-a (account)
"Fixes `beancount-electric-currency', which could never find the currency
for the current account. Also allows it to fall back to the operating_currency."
:override #'beancount--account-currency
(save-excursion
(goto-char (point-min))
(when (or (re-search-forward
(concat "^" beancount-date-regexp " +open"
"\\s-+" (regexp-quote account)
"\\s-+\\(" beancount-currency-regexp "\\)\\>")
nil t)
(re-search-forward
(concat "^option\\s-+\"operating_currency\"\\s-+\"\\("
beancount-currency-regexp
"\\)\"")
nil t))
(match-string-no-properties 1)))))