Skip to content

Commit

Permalink
Refactor and simplify company backends declaration
Browse files Browse the repository at this point in the history
Enabling a company backend for a specific mode was a tedious tasks with code
scattered at different locations, one for local variable definitions, one for
company hook function definitions and another where the backends were pushed to
the local variables (which was problematic, since we ended up pushing the same
backends over and over again with `SPC f e R`, pushes have been replaced by
add-to-list calls in the new macro).

All these steps are now put together at one place with the new macro
spacemacs|add-company-backends, check its docstring for more info on its
arguments.

This macro also allows to define arbitrary buffer local variables to tune
company for specific modes (similar to layer variables via a keyword :variables)

The code related to company backends management has been moved to the
auto-completion layer in the funcs.el file. A nice side effect of this move is
that it enforces correct encapsulation of company backends related code. We can
now easily detect if there is some configuration leakage when the
auto-completion layer is not used. But we loose macro expansion at file loading
time (not sue it is a big concern though).

The function spacemacs|enable-auto-complete was never used so it has been
deleted which led to the deletion of the now empty file core-auto-completion.el.

The example in LAYERS.org regarding auto-completion is now out of date and has
been deleted. An example to setup auto-completion is provided in the README.org
file of the auto-completion layer.
  • Loading branch information
syl20bnr committed Jan 2, 2017
1 parent bdd4e6c commit 74fdbb6
Show file tree
Hide file tree
Showing 89 changed files with 330 additions and 565 deletions.
83 changes: 0 additions & 83 deletions core/core-auto-completion.el

This file was deleted.

1 change: 0 additions & 1 deletion core/core-spacemacs.el
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
(require 'core-dotspacemacs)
(require 'core-custom-settings)
(require 'core-release-management)
(require 'core-auto-completion)
(require 'core-jump)
(require 'core-display-init)
(require 'core-themes-support)
Expand Down
54 changes: 0 additions & 54 deletions doc/LAYERS.org
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@
- [[#load-ordering][Load ordering]]
- [[#no-require][No require]]
- [[#auto-load-everything][Auto-load everything]]
- [[#how-do-i--idiomatically][How do I ... idiomatically?]]
- [[#setup-auto-completion-for-a-major-mode][Setup auto-completion for a major mode]]

* Introduction
This document is intended as a tutorial for users who are interested in writing
Expand Down Expand Up @@ -463,7 +461,6 @@ would have been installed even if the =auto-completion= layer had been disabled,
which is not what we want.

* Layer tips and tricks

** Cross-dependencies
Spacemacs provides a couple of additional useful functions you can use to check
whether other layers or packages are included.
Expand Down Expand Up @@ -570,54 +567,3 @@ missing appropriate auto-loads.
Defer everything. You should have a very good reason not to defer the loading
of a package.

* How do I ... idiomatically?

** Setup auto-completion for a major mode
In your layer's =config.el=, call =spacemacs|defvar-company-backends=.

#+begin_src emacs-lisp
(spacemacs|defvar-company-backends yoyo-mode)
#+end_src

This creates a variable called =company-backends-yoyo-mode=. In the package
=init= functions, you should push backends to this variable. But of course, only
if the =auto-completion= layer is enabled.

#+begin_src emacs-lisp
(defconst yoyo-packages '(
;; ...
some-weird-package
;; ...
)

(when (configuration-layer/package-usedp 'company)
(defun yoyo/init-some-weird-package ()
(use-package some-weird-package
:defer t
;; This has to be in init because it's a package entry point
:init
(push 'some-weird-backend company-backends-yoyo-mode))))
#+end_src

Finally, we must make sure company is started when we enter =yoyo-mode=, but
again only if the =auto-completion= layer is enabled.

#+begin_src emacs-lisp
(defconst yoyo-packages '(
;; ...
yoyo-mode
;; ...
))

(defun yoyo/init-yoyo-mode ()
(use-package yoyo-mode
;; Some configuration goes here, however nothing relating to company
;; since this function may be called even if company is not installed!
))

(when (configuration-layer/package-usedp 'company)
(defun yoyo/post-init-yoyo-mode ()
;; This makes no reference to `some-weird-package', which may have
;; been excluded by the user
(spacemacs|add-company-hook yoyo-mode)))
#+end_src
2 changes: 0 additions & 2 deletions layers/+chat/erc/config.el
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,3 @@

(defvar erc-server-list nil
"If non nil, connect automatically to the specified servers with the given credentials.")

(spacemacs|defvar-company-backends erc-mode)
5 changes: 2 additions & 3 deletions layers/+chat/erc/packages.el
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,10 @@
(push 'erc-terminal-notifier erc-packages))

(defun erc/post-init-company ()
(spacemacs|add-company-hook erc-mode)
(push 'company-capf company-backends-erc-mode))
(spacemacs|add-company-backends :backends company-capf :modes erc-mode))

(defun erc/post-init-company-emoji ()
(push 'company-emoji company-backends-erc-mode))
(spacemacs|add-company-backends :backends company-emoji :modes erc-mode))

(defun erc/post-init-emoji-cheat-sheet-plus ()
(add-hook 'erc-mode-hook 'emoji-cheat-sheet-plus-display-mode))
Expand Down
2 changes: 0 additions & 2 deletions layers/+chat/rcirc/config.el
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,3 @@

(defvar rcirc-spacemacs-layout-binding "i"
"Binding used in the setup for `spacemacs-layouts' micro-state")

(spacemacs|defvar-company-backends rcirc-mode)
5 changes: 2 additions & 3 deletions layers/+chat/rcirc/packages.el
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
))

(defun rcirc/post-init-company ()
(spacemacs|add-company-hook rcirc-mode)
(push 'company-capf company-backends-rcirc-mode))
(spacemacs|add-company-backends :backends company-capf :modes rcirc-mode))

(defun rcirc/post-init-company-emoji ()
(push 'company-emoji company-backends-rcirc-mode))
(spacemacs|add-company-backends :backends company-emoji :modes rcirc-mode))

(defun rcirc/post-init-emoji-cheat-sheet-plus ()
(add-hook 'rcirc-mode-hook 'emoji-cheat-sheet-plus-display-mode))
Expand Down
24 changes: 8 additions & 16 deletions layers/+completion/auto-completion/README.org
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
- [[#enable-company-or-auto-complete-globally][Enable company or auto-complete globally]]
- [[#replacing-company-by-auto-complete][Replacing company by auto-complete]]
- [[#add-auto-completion-in-a-layer][Add auto-completion in a layer]]
- [[#in-configel][In =config.el=]]
- [[#in-packagesel][In =packages.el=]]
- [[#completion-back-ends][Completion back ends]]
- [[#improved-faces][Improved faces]]
- [[#key-bindings-1][Key Bindings]]
Expand Down Expand Up @@ -152,32 +150,26 @@ You can disable =company= by adding it to the =dotspacemacs-excluded-packages=
variable, then you are free to enable =auto-complete= globally.

** Add auto-completion in a layer
Here is an example to add =company= auto-completion to python buffer:
Here is an example to add =company= auto-completion to python buffers via the
package =company-anaconda=.

*** In =config.el=
#+BEGIN_SRC emacs-lisp
;; Define the buffer local company backend variable
(spacemacs|defvar-company-backends python-mode)
#+END_SRC
In the file =packages.el= of the python layer:

*** In =packages.el=
#+BEGIN_SRC emacs-lisp
;; Add the relevant packages to the layer
;; here it is `company-anaconda'
(setq python-packages
'(...
company
(company-anaconda :toggle (configuration-layer/package-usedp 'company))
...))

;; Hook company to python-mode
(defun python/post-init-company ()
(spacemacs|add-company-hook python-mode))

;; Add the backend to the major-mode specific backend list
(defun python/init-company-anaconda ()
(use-package company-anaconda
:defer t
:init (push 'company-anaconda company-backends-python-mode)))
:init
(spacemacs|add-company-backends
:backends 'company-anaconda
:modes python-mode)))
#+END_SRC

** Completion back ends
Expand Down
8 changes: 8 additions & 0 deletions layers/+completion/auto-completion/config.el
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@

;; Company -------------------------------------------------------------------

(defvar spacemacs-default-company-backends
'((company-dabbrev-code company-gtags company-etags company-keywords)
company-files company-dabbrev)
"The list of default company backends used by spacemacs.
This variable is used to configure mode-specific company backends in spacemacs.
Backends in this list will always be active in these modes, as well as any
backends added by individual spacemacs layers.")

(defvar-local auto-completion-front-end 'company
"Which auto-completion front end to use.")

Expand Down
94 changes: 94 additions & 0 deletions layers/+completion/auto-completion/funcs.el
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,100 @@
:documentation "Enable auto-completion."
:evil-leader "ta")


;; company backends declaration macro

(defmacro spacemacs|add-company-backends (&rest props)
"Add and enable company backends.
This function should be called exclusively in `post-init-company' functions or
`init-company-xxx' function where xxx is company backend package.
Available PROPS:
`:backends BACKENDS'
One or several symbols or lists representing a company backend or a list of
company backends.
`:modes MODES'
One or several modes where BACKENDS will be added.
`:variables VAR VALUE'
One or several VAR VALUE pairs (similar to layer variables).
These variables are made buffer local so their values are set only for
the given MODES.
`:from SYMBOL'
Advanced property aimed at avoiding hook function name conflicts when
`:variables' property is used in several calls to this macro for the same
MODES."
(declare (indent 0))
(let* ((backends (spacemacs/mplist-get props :backends))
(modes (spacemacs/mplist-get props :modes))
(variables (spacemacs/mplist-get props :variables))
(from (plist-get props :from))
(result '(progn)))
(dolist (mode modes)
(let ((backends-var-name (intern (format "company-backends-%S" mode)))
(init-func-name (intern (format "spacemacs//init-company-%S" mode)))
(vars-func-name (intern
(format "spacemacs//init-company-vars-%S%s" mode
(if from (format "-%S" from) ""))))
(mode-hook-name (intern (format "%S-hook" mode))))
;; declare buffer local company-backends variable
(push `(defvar ,backends-var-name
',spacemacs-default-company-backends
,(format "Company backend list for %S." mode)) result)
;; add backends
(dolist (backend backends)
(push `(add-to-list ',backends-var-name ',backend) result))
;; define initialization hook function
(push `(defun ,init-func-name ()
,(format "Initialize company for %S." mode)
(when auto-completion-enable-snippets-in-popup
(setq ,backends-var-name
(mapcar 'spacemacs//show-snippets-in-company
,backends-var-name)))
(set (make-variable-buffer-local 'auto-completion-front-end)
'company)
(set (make-variable-buffer-local 'company-backends)
,backends-var-name)) result)
(push `(add-hook ',mode-hook-name ',init-func-name t) result)
;; define variables hook function
(when variables
(let ((vars-func `(defun ,vars-func-name ()
,(format "Define company local variables for %S."
mode)))
vars)
(while variables
(let* ((var (pop variables))
(forms
(when (consp variables)
`(set (make-variable-buffer-local ',var)
,(eval (pop variables))))))
(when forms (push forms vars))))
(push (append vars-func vars) result))
(push `(add-hook ',mode-hook-name ',vars-func-name t) result))
(push `(add-hook ',mode-hook-name 'company-mode t) result)))
;; return the expanded macro in correct order
(reverse result)))

(defmacro spacemacs|disable-company (mode)
"Disable company for the given MODE.
MODE parameter must match the :modes values used in the call to
`spacemacs|add-company-backends'."
(let ((mode-hook-name (intern (format "%S-hook" mode)))
(func (intern (format "spacemacs//init-company-%S" mode))))
`(progn
(remove-hook ',mode-hook-name ',func)
(remove-hook ',mode-hook-name 'company-mode))))

(defun spacemacs//show-snippets-in-company (backend)
(if (or (not auto-completion-enable-snippets-in-popup)
(and (listp backend) (member 'company-yasnippet backend)))
backend
(append (if (consp backend) backend (list backend))
'(:with company-yasnippet))))


;; auto-completion key bindings functions

Expand Down
2 changes: 0 additions & 2 deletions layers/+emacs/org/config.el
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,3 @@ used.")

(defvar org-enable-org-journal-support nil
"If non-nil org-journal is configured.")

(spacemacs|defvar-company-backends org-mode)
5 changes: 2 additions & 3 deletions layers/+emacs/org/packages.el
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,10 @@
))

(defun org/post-init-company ()
(spacemacs|add-company-hook org-mode)
(push 'company-capf company-backends-org-mode))
(spacemacs|add-company-backends :backends company-capf :modes org-mode))

(defun org/post-init-company-emoji ()
(push 'company-emoji company-backends-org-mode))
(spacemacs|add-company-backends :backends company-emoji :modes org-mode))

(defun org/post-init-emoji-cheat-sheet-plus ()
(add-hook 'org-mode-hook 'spacemacs/delay-emoji-cheat-sheet-hook))
Expand Down
2 changes: 0 additions & 2 deletions layers/+frameworks/react/config.el
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,4 @@

;; Variables

(spacemacs|defvar-company-backends react-mode)

(spacemacs|define-jump-handlers react-mode)
Loading

0 comments on commit 74fdbb6

Please sign in to comment.