completion/company: refactor backend resolution

Makes it easier to change company-backends retrospectively (with a hook
or setq-hook!). Also simplifies how backend defaults are stored (no more
of this :derived and :exact business).

Also updates unit tests.
This commit is contained in:
Henrik Lissner 2019-06-29 01:34:10 +02:00
parent 2f268e80bb
commit 281ea56643
No known key found for this signature in database
GPG key ID: 5F6C0EA160557395
2 changed files with 40 additions and 41 deletions

View file

@ -2,9 +2,9 @@
;;;###autoload ;;;###autoload
(defvar +company-backend-alist (defvar +company-backend-alist
'((text-mode :derived (company-dabbrev company-yasnippet company-ispell)) '((text-mode company-dabbrev company-yasnippet company-ispell)
(prog-mode :derived (:separate company-capf company-yasnippet)) (prog-mode company-capf company-yasnippet)
(conf-mode :derived company-capf company-dabbrev-code company-yasnippet)) (conf-mode company-capf company-dabbrev-code company-yasnippet))
"An alist matching modes to company backends. The backends for any mode is "An alist matching modes to company backends. The backends for any mode is
built from this.") built from this.")
@ -28,40 +28,37 @@ Examples:
(set-company-backend! '(c-mode c++-mode) (set-company-backend! '(c-mode c++-mode)
'(:separate company-irony-c-headers company-irony)) '(:separate company-irony-c-headers company-irony))
(set-company-backend! 'sh-mode nil) ; unsets backends for sh-mode (set-company-backend! 'sh-mode nil) ; unsets backends for sh-mode"
To have BACKENDS apply to any mode that is a parent of MODES, set MODES to
:derived, e.g.
(set-company-backend! :derived 'text-mode 'company-dabbrev 'company-yasnippet)"
(declare (indent defun)) (declare (indent defun))
(let ((type :exact))
(when (eq modes :derived)
(setq type :derived
modes (pop backends)))
(dolist (mode (doom-enlist modes)) (dolist (mode (doom-enlist modes))
(if (null (car backends)) (if (null (car backends))
(setq +company-backend-alist (setq +company-backend-alist
(delq (assq mode +company-backend-alist) (delq (assq mode +company-backend-alist)
+company-backend-alist)) +company-backend-alist))
(setf (alist-get mode +company-backend-alist) (setf (alist-get mode +company-backend-alist)
(cons type backends)))))) backends))))
;; ;;
;;; Library ;;; Library
(defun +company--backends () (defun +company--backends ()
(append (cl-loop for (mode . rest) in +company-backend-alist (let (backends)
for type = (car rest) (let ((mode major-mode)
for backends = (cdr rest) (modes (list major-mode)))
if (or (and (eq type :derived) (derived-mode-p mode)) ; parent modes (while (setq mode (get mode 'derived-mode-parent))
(and (eq type :exact) (push mode modes))
(or (eq major-mode mode) ; major modes (dolist (mode modes)
(and (boundp mode) (dolist (backend (append (cdr (assq mode +company-backend-alist))
(symbol-value mode))))) ; minor modes
append backends)
(default-value 'company-backends))) (default-value 'company-backends)))
(push backend backends)))
(delete-dups
(append (cl-loop for (mode . backends) in +company-backend-alist
if (or (eq major-mode mode) ; major modes
(and (boundp mode)
(symbol-value mode))) ; minor modes
append backends)
(nreverse backends))))))
;; ;;
@ -70,9 +67,11 @@ To have BACKENDS apply to any mode that is a parent of MODES, set MODES to
;;;###autoload ;;;###autoload
(defun +company|init-backends () (defun +company|init-backends ()
"Set `company-backends' for the current buffer." "Set `company-backends' for the current buffer."
(if (not company-mode)
(remove-hook 'change-major-mode-after-body-hook #'+company|init-backends 'local)
(unless (eq major-mode 'fundamental-mode) (unless (eq major-mode 'fundamental-mode)
(set (make-local-variable 'company-backends) (+company--backends))) (setq-local company-backends (+company--backends)))
(add-hook 'after-change-major-mode-hook #'+company|init-backends nil 'local)) (add-hook 'change-major-mode-after-body-hook #'+company|init-backends nil 'local)))
(put '+company|init-backends 'permanent-local-hook t) (put '+company|init-backends 'permanent-local-hook t)

View file

@ -26,7 +26,7 @@
(expect (backends 'text-mode) :to-equal '(a t))) (expect (backends 'text-mode) :to-equal '(a t)))
(it "sets backends for a derived-mode" (it "sets backends for a derived-mode"
(set-company-backend! :derived 'prog-mode 'a) (set-company-backend! 'prog-mode 'a)
(expect (backends 'prog-mode) :to-equal '(a t)) (expect (backends 'prog-mode) :to-equal '(a t))
(expect (backends 'emacs-lisp-mode) :to-equal '(a t))) (expect (backends 'emacs-lisp-mode) :to-equal '(a t)))
@ -35,12 +35,12 @@
(expect (backends 'text-mode) :to-equal (backends 'emacs-lisp-mode))) (expect (backends 'text-mode) :to-equal (backends 'emacs-lisp-mode)))
(it "sets cumulative backends" (it "sets cumulative backends"
(set-company-backend! :derived 'prog-mode '(a b c)) (set-company-backend! 'prog-mode '(a b c))
(set-company-backend! 'emacs-lisp-mode 'd 'e) (set-company-backend! 'emacs-lisp-mode 'd 'e)
(expect (backends 'emacs-lisp-mode) :to-equal '(d e (a b c) t))) (expect (backends 'emacs-lisp-mode) :to-equal '(d e (a b c) t)))
(it "sets cumulative backends with a minor mode" (it "sets cumulative backends with a minor mode"
(set-company-backend! :derived 'prog-mode '(a b c)) (set-company-backend! 'prog-mode '(a b c))
(set-company-backend! 'emacs-lisp-mode 'd 'e) (set-company-backend! 'emacs-lisp-mode 'd 'e)
(set-company-backend! 'some-minor-mode 'x 'y) (set-company-backend! 'some-minor-mode 'x 'y)
(setq-local some-minor-mode t) (setq-local some-minor-mode t)
@ -57,19 +57,19 @@
(expect (backends 'text-mode) :to-equal (default-value 'company-backends))) (expect (backends 'text-mode) :to-equal (default-value 'company-backends)))
(it "unsets past parent backends" (it "unsets past parent backends"
(set-company-backend! :derived 'prog-mode 'old) (set-company-backend! 'prog-mode 'old)
(set-company-backend! 'emacs-lisp-mode 'child) (set-company-backend! 'emacs-lisp-mode 'child)
(set-company-backend! :derived 'prog-mode nil) (set-company-backend! 'prog-mode nil)
(expect (backends 'emacs-lisp-mode) :to-equal '(child t))) (expect (backends 'emacs-lisp-mode) :to-equal '(child t)))
(it "overwrites past cumulative backends" (it "overwrites past cumulative backends"
(set-company-backend! :derived 'prog-mode 'base) (set-company-backend! 'prog-mode 'base)
(set-company-backend! 'emacs-lisp-mode 'old) (set-company-backend! 'emacs-lisp-mode 'old)
(set-company-backend! 'emacs-lisp-mode 'new) (set-company-backend! 'emacs-lisp-mode 'new)
(expect (backends 'emacs-lisp-mode) :to-equal '(new base t))) (expect (backends 'emacs-lisp-mode) :to-equal '(new base t)))
(it "overwrites past parent backends" (it "overwrites past parent backends"
(set-company-backend! :derived 'prog-mode 'base) (set-company-backend! 'prog-mode 'base)
(set-company-backend! 'emacs-lisp-mode 'child) (set-company-backend! 'emacs-lisp-mode 'child)
(set-company-backend! :derived 'prog-mode 'new) (set-company-backend! 'prog-mode 'new)
(expect (backends 'emacs-lisp-mode) :to-equal '(child new t))))) (expect (backends 'emacs-lisp-mode) :to-equal '(child new t)))))