2015-04-03 04:28:13 +00:00
|
|
|
|
;;; funcs.el --- Auto-completion functions File
|
|
|
|
|
;;
|
2018-01-04 07:00:25 +00:00
|
|
|
|
;; Copyright (c) 2012-2018 Sylvain Benner & Contributors
|
2015-04-03 04:28:13 +00:00
|
|
|
|
;;
|
|
|
|
|
;; Author: Sylvain Benner <sylvain.benner@gmail.com>
|
|
|
|
|
;; URL: https://github.com/syl20bnr/spacemacs
|
|
|
|
|
;;
|
|
|
|
|
;; This file is not part of GNU Emacs.
|
|
|
|
|
;;
|
|
|
|
|
;;; License: GPLv3
|
|
|
|
|
|
2016-04-22 01:35:27 +00:00
|
|
|
|
|
|
|
|
|
|
2015-04-03 04:28:13 +00:00
|
|
|
|
(spacemacs|add-toggle auto-completion
|
2015-07-25 13:14:53 +00:00
|
|
|
|
:status
|
2016-03-06 22:20:03 +00:00
|
|
|
|
(if (eq 'company auto-completion-front-end)
|
|
|
|
|
(bound-and-true-p company-mode)
|
|
|
|
|
(bound-and-true-p auto-complete-mode))
|
2015-07-25 13:14:53 +00:00
|
|
|
|
:on
|
|
|
|
|
(progn
|
|
|
|
|
(if (eq 'company auto-completion-front-end)
|
|
|
|
|
(company-mode)
|
|
|
|
|
(auto-complete-mode))
|
|
|
|
|
(message "Enabled auto-completion (using %S)."
|
|
|
|
|
auto-completion-front-end))
|
|
|
|
|
:off
|
|
|
|
|
(progn
|
|
|
|
|
(if (eq 'company auto-completion-front-end)
|
|
|
|
|
(company-mode -1)
|
|
|
|
|
(auto-complete-mode -1))
|
|
|
|
|
(message "Disabled auto-completion."))
|
2015-08-27 06:58:05 +00:00
|
|
|
|
:documentation "Enable auto-completion."
|
2015-07-25 13:14:53 +00:00
|
|
|
|
:evil-leader "ta")
|
2015-04-03 04:28:13 +00:00
|
|
|
|
|
2017-01-02 05:39:04 +00:00
|
|
|
|
|
|
|
|
|
;; 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
|
2017-02-11 05:29:09 +00:00
|
|
|
|
MODES.
|
|
|
|
|
|
|
|
|
|
`:hook BOOLEAN'
|
|
|
|
|
Advanced property to control whether hooks functions are hooked or not,
|
|
|
|
|
if non-nil hook functions are appended to modes hooks passed as `:modes'."
|
2017-01-02 05:39:04 +00:00
|
|
|
|
(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))
|
2017-02-11 05:29:09 +00:00
|
|
|
|
(hooks (if (memq :hooks props)
|
|
|
|
|
(plist-get props :hooks)
|
|
|
|
|
t))
|
2017-01-02 05:39:04 +00:00
|
|
|
|
(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
|
2017-03-19 16:36:59 +00:00
|
|
|
|
spacemacs-default-company-backends
|
2017-01-02 05:39:04 +00:00
|
|
|
|
,(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)
|
2017-02-11 05:29:09 +00:00
|
|
|
|
(when hooks
|
|
|
|
|
(push `(add-hook ',mode-hook-name ',init-func-name t) result))
|
2017-01-02 05:39:04 +00:00
|
|
|
|
;; 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))
|
2017-02-11 05:29:09 +00:00
|
|
|
|
(when hooks
|
|
|
|
|
(push `(add-hook ',mode-hook-name ',vars-func-name t) result)))
|
|
|
|
|
(when hooks
|
|
|
|
|
(push `(add-hook ',mode-hook-name 'company-mode t) result))))
|
2017-01-02 05:39:04 +00:00
|
|
|
|
;; 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))))
|
|
|
|
|
|
2016-04-22 01:35:27 +00:00
|
|
|
|
|
2015-05-04 04:13:58 +00:00
|
|
|
|
;; auto-completion key bindings functions
|
2015-04-03 04:28:13 +00:00
|
|
|
|
|
2015-05-06 02:32:28 +00:00
|
|
|
|
(defun spacemacs//auto-completion-set-RET-key-behavior (package)
|
|
|
|
|
"Bind RET key appropriately for the given PACKAGE and value of
|
|
|
|
|
`auto-completion-return-key-behavior'."
|
2015-05-04 04:13:58 +00:00
|
|
|
|
(cond
|
|
|
|
|
((eq 'company package)
|
|
|
|
|
(let ((map company-active-map))
|
|
|
|
|
(cond
|
2015-05-06 02:32:28 +00:00
|
|
|
|
((eq 'complete auto-completion-return-key-behavior)
|
2015-05-04 04:13:58 +00:00
|
|
|
|
(define-key map [return] 'company-complete-selection)
|
|
|
|
|
(define-key map (kbd "RET") 'company-complete-selection))
|
|
|
|
|
(t
|
|
|
|
|
(define-key map [return] 'nil)
|
|
|
|
|
(define-key map (kbd "RET") 'nil)))))
|
|
|
|
|
(t (message "Not yet implemented for package %S" package))))
|
|
|
|
|
|
2015-05-06 02:32:28 +00:00
|
|
|
|
(defun spacemacs//auto-completion-set-TAB-key-behavior (package)
|
|
|
|
|
"Bind TAB key appropriately for the given PACKAGE and value of
|
|
|
|
|
`auto-completion-tab-key-behavior'."
|
2015-05-04 04:13:58 +00:00
|
|
|
|
(cond
|
|
|
|
|
((eq 'company package)
|
|
|
|
|
(let ((map company-active-map))
|
|
|
|
|
(cond
|
2015-05-06 02:32:28 +00:00
|
|
|
|
((eq 'complete auto-completion-tab-key-behavior)
|
2015-05-04 04:13:58 +00:00
|
|
|
|
(define-key map (kbd "TAB") 'company-complete-selection)
|
|
|
|
|
(define-key map (kbd "<tab>") 'company-complete-selection))
|
2015-05-06 02:32:28 +00:00
|
|
|
|
((eq 'cycle auto-completion-tab-key-behavior)
|
2015-05-04 04:13:58 +00:00
|
|
|
|
(define-key map (kbd "TAB") 'company-complete-common-or-cycle)
|
|
|
|
|
(define-key map (kbd "<tab>") 'company-complete-common-or-cycle)
|
|
|
|
|
(define-key map (kbd "<S-tab>")
|
|
|
|
|
'spacemacs//company-complete-common-or-cycle-backward)
|
|
|
|
|
(define-key map (kbd "<backtab>")
|
|
|
|
|
'spacemacs//company-complete-common-or-cycle-backward))
|
|
|
|
|
(t
|
|
|
|
|
(define-key map (kbd "TAB") nil)
|
|
|
|
|
(define-key map (kbd "<tab>") nil)))))
|
|
|
|
|
(t (message "Not yet implemented for package %S" package))))
|
|
|
|
|
|
2015-05-06 02:32:28 +00:00
|
|
|
|
(defun spacemacs//auto-completion-setup-key-sequence (package)
|
|
|
|
|
"Setup the key sequence to complete current selection."
|
|
|
|
|
(when auto-completion-complete-with-key-sequence
|
|
|
|
|
(let ((first-key (elt auto-completion-complete-with-key-sequence 0)))
|
|
|
|
|
(cond ((eq 'company package)
|
|
|
|
|
(define-key company-active-map (kbd (char-to-string first-key))
|
|
|
|
|
'spacemacs//auto-completion-key-sequence-start))
|
|
|
|
|
(t (message "Not yet implemented for package %S" package))))))
|
2015-05-04 04:13:58 +00:00
|
|
|
|
|
2016-04-22 01:35:27 +00:00
|
|
|
|
|
2015-05-04 04:13:58 +00:00
|
|
|
|
;; key sequence to complete selection
|
|
|
|
|
|
|
|
|
|
(defvar spacemacs--auto-completion-time nil)
|
|
|
|
|
(defvar spacemacs--auto-completion-complete-last-candidate nil)
|
2015-05-06 02:32:28 +00:00
|
|
|
|
(defvar spacemacs--auto-completion-shadowed-insert-binding nil)
|
|
|
|
|
(defvar spacemacs--auto-completion-shadowed-emacs-binding nil)
|
2016-06-12 20:20:21 +00:00
|
|
|
|
(defvar spacemacs--auto-completion-shadowed-hybrid-binding nil)
|
2015-05-04 04:13:58 +00:00
|
|
|
|
|
|
|
|
|
(defun spacemacs//auto-completion-key-sequence-start ()
|
|
|
|
|
"Initiate auto-completion sequence."
|
|
|
|
|
(interactive)
|
|
|
|
|
(self-insert-command 1)
|
|
|
|
|
(setq spacemacs--auto-completion-complete-last-candidate
|
|
|
|
|
(cond
|
|
|
|
|
((bound-and-true-p company-mode)
|
|
|
|
|
(nth company-selection company-candidates))))
|
2015-05-06 02:32:28 +00:00
|
|
|
|
;; enable second key of the sequence
|
|
|
|
|
(let ((second-key (kbd (char-to-string
|
|
|
|
|
(elt auto-completion-complete-with-key-sequence 1)))))
|
|
|
|
|
(setq spacemacs--auto-completion-shadowed-insert-binding
|
|
|
|
|
(lookup-key evil-insert-state-map second-key))
|
|
|
|
|
(setq spacemacs--auto-completion-shadowed-emacs-binding
|
|
|
|
|
(lookup-key evil-emacs-state-map second-key))
|
2016-06-12 20:20:21 +00:00
|
|
|
|
(setq spacemacs--auto-completion-shadowed-hybrid-binding
|
|
|
|
|
(lookup-key evil-hybrid-state-map second-key))
|
2015-05-06 02:32:28 +00:00
|
|
|
|
(define-key
|
|
|
|
|
evil-insert-state-map
|
|
|
|
|
second-key
|
|
|
|
|
'spacemacs//auto-completion-key-sequence-end)
|
|
|
|
|
(define-key
|
|
|
|
|
evil-emacs-state-map
|
|
|
|
|
second-key
|
2016-06-12 20:20:21 +00:00
|
|
|
|
'spacemacs//auto-completion-key-sequence-end)
|
|
|
|
|
(define-key
|
|
|
|
|
evil-hybrid-state-map
|
|
|
|
|
second-key
|
2015-05-06 02:32:28 +00:00
|
|
|
|
'spacemacs//auto-completion-key-sequence-end))
|
|
|
|
|
;; set a timer to restore the old bindings
|
2015-07-24 12:16:20 +00:00
|
|
|
|
(run-at-time auto-completion-complete-with-key-sequence-delay
|
|
|
|
|
nil
|
|
|
|
|
'spacemacs//auto-completion-key-sequence-restore)
|
2015-05-04 04:13:58 +00:00
|
|
|
|
(when spacemacs--auto-completion-complete-last-candidate
|
|
|
|
|
(setq spacemacs--auto-completion-time (current-time))))
|
|
|
|
|
|
|
|
|
|
(defun spacemacs//auto-completion-key-sequence-end ()
|
|
|
|
|
"Check if the auto-completion key sequence has been entered."
|
|
|
|
|
(interactive)
|
|
|
|
|
(if (or (null spacemacs--auto-completion-time)
|
2015-07-24 12:16:20 +00:00
|
|
|
|
(< auto-completion-complete-with-key-sequence-delay
|
|
|
|
|
(float-time (time-since spacemacs--auto-completion-time))))
|
2015-05-04 04:13:58 +00:00
|
|
|
|
(self-insert-command 1)
|
|
|
|
|
(cond
|
|
|
|
|
((bound-and-true-p company-mode)
|
|
|
|
|
(unless company-candidates
|
2015-05-06 02:32:28 +00:00
|
|
|
|
;; if the auto-completion menu is still active then we don't need to
|
|
|
|
|
;; delete the last inserted first key of the sequence
|
|
|
|
|
(delete-char -1))
|
2015-05-04 04:13:58 +00:00
|
|
|
|
(let ((company-idle-delay))
|
|
|
|
|
(company-auto-begin)
|
|
|
|
|
(company-finish spacemacs--auto-completion-complete-last-candidate)))))
|
2015-05-06 02:32:28 +00:00
|
|
|
|
(spacemacs//auto-completion-key-sequence-restore)
|
2015-05-04 04:13:58 +00:00
|
|
|
|
(setq spacemacs--auto-completion-time nil))
|
2015-05-06 02:32:28 +00:00
|
|
|
|
|
|
|
|
|
(defun spacemacs//auto-completion-key-sequence-restore ()
|
|
|
|
|
"Restore the shadowed key bindings used to auto-complete."
|
|
|
|
|
(let ((second-key (kbd (char-to-string
|
|
|
|
|
(elt auto-completion-complete-with-key-sequence 1)))))
|
|
|
|
|
(define-key
|
|
|
|
|
evil-insert-state-map
|
|
|
|
|
second-key
|
|
|
|
|
spacemacs--auto-completion-shadowed-insert-binding)
|
|
|
|
|
(define-key
|
|
|
|
|
evil-emacs-state-map
|
|
|
|
|
second-key
|
2016-06-12 20:20:21 +00:00
|
|
|
|
spacemacs--auto-completion-shadowed-emacs-binding)
|
|
|
|
|
(define-key
|
|
|
|
|
evil-hybrid-state-map
|
|
|
|
|
second-key
|
|
|
|
|
spacemacs--auto-completion-shadowed-hybrid-binding)))
|
2016-04-22 01:35:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; Editing style
|
|
|
|
|
|
|
|
|
|
(defun spacemacs//company-active-navigation (style)
|
|
|
|
|
"Set navigation for the given editing STYLE."
|
|
|
|
|
(cond
|
|
|
|
|
((or (eq 'vim style)
|
|
|
|
|
(and (eq 'hybrid style)
|
|
|
|
|
hybrid-mode-enable-hjkl-bindings))
|
|
|
|
|
(let ((map company-active-map))
|
|
|
|
|
(define-key map (kbd "C-j") 'company-select-next)
|
|
|
|
|
(define-key map (kbd "C-k") 'company-select-previous)
|
2016-08-29 12:58:50 +00:00
|
|
|
|
(define-key map (kbd "C-l") 'company-complete-selection))
|
|
|
|
|
(when (require 'company-quickhelp nil 'noerror)
|
|
|
|
|
(evil-define-key 'insert company-quickhelp-mode-map (kbd "C-k") 'company-select-previous)))
|
2016-04-22 01:35:27 +00:00
|
|
|
|
(t
|
|
|
|
|
(let ((map company-active-map))
|
|
|
|
|
(define-key map (kbd "C-n") 'company-select-next)
|
2017-12-28 07:43:37 +00:00
|
|
|
|
(define-key map (kbd "C-p") 'company-select-previous)))))
|
2016-04-22 01:35:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; Transformers
|
|
|
|
|
|
|
|
|
|
(defun spacemacs//company-transformer-cancel (candidates)
|
|
|
|
|
"Cancel completion if prefix is in the list
|
|
|
|
|
`company-mode-completion-cancel-keywords'"
|
|
|
|
|
(unless (member company-prefix company-mode-completion-cancel-keywords)
|
|
|
|
|
candidates))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(defvar-local company-fci-mode-on-p nil)
|
|
|
|
|
|
|
|
|
|
(defun company-turn-off-fci (&rest ignore)
|
|
|
|
|
(when (boundp 'fci-mode)
|
|
|
|
|
(setq company-fci-mode-on-p fci-mode)
|
|
|
|
|
(when fci-mode (fci-mode -1))))
|
|
|
|
|
|
|
|
|
|
(defun company-maybe-turn-on-fci (&rest ignore)
|
|
|
|
|
(when company-fci-mode-on-p (fci-mode 1)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; helm-yas
|
|
|
|
|
|
|
|
|
|
(defun spacemacs/helm-yas ()
|
|
|
|
|
"Properly lazy load helm-c-yasnipper."
|
|
|
|
|
(interactive)
|
|
|
|
|
(spacemacs/load-yasnippet)
|
|
|
|
|
(require 'helm-c-yasnippet)
|
|
|
|
|
(call-interactively 'helm-yas-complete))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; Yasnippet
|
|
|
|
|
|
|
|
|
|
(defun spacemacs/load-yasnippet ()
|
|
|
|
|
(unless yas-global-mode (yas-global-mode 1))
|
|
|
|
|
(yas-minor-mode 1))
|
|
|
|
|
|
|
|
|
|
(defun spacemacs/force-yasnippet-off ()
|
|
|
|
|
(yas-minor-mode -1)
|
|
|
|
|
(setq yas-dont-activate t))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; Auto-Yasnippet
|
|
|
|
|
|
|
|
|
|
(defun spacemacs/auto-yasnippet-expand ()
|
|
|
|
|
"Call `yas-expand' and switch to `insert state'"
|
|
|
|
|
(interactive)
|
|
|
|
|
(call-interactively 'aya-expand)
|
2016-10-29 13:11:36 +00:00
|
|
|
|
(evil-insert-state))
|
2016-08-07 17:35:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; Yasnippet and Smartparens
|
|
|
|
|
|
|
|
|
|
;; If enabled, smartparens will mess snippets expanded by `hippie-expand`.
|
|
|
|
|
;; We want to temporarily disable Smartparens during the snippet expansion and
|
|
|
|
|
;; switch it back to the initial state when done.
|
|
|
|
|
;;
|
|
|
|
|
;; However, there is an asymmetry in Yasnippet's hooks:
|
|
|
|
|
;; * `yas-before-expand-snippet-hook' is called for all snippet expansions,
|
|
|
|
|
;; including the nested ones.
|
|
|
|
|
;; * `yas-after-exit-snippet-hook' is called only for the top level snippet,
|
|
|
|
|
;; but NOT for the nested ones.
|
|
|
|
|
;;
|
|
|
|
|
;; That's why we introduce `spacemacs--yasnippet-expanding' below.
|
|
|
|
|
|
|
|
|
|
(defvar spacemacs--smartparens-enabled-initially t
|
|
|
|
|
"Stored whether smartparens is originally enabled or not.")
|
|
|
|
|
(defvar spacemacs--yasnippet-expanding nil
|
|
|
|
|
"Whether the snippet expansion is in progress.")
|
|
|
|
|
|
|
|
|
|
(defun spacemacs//smartparens-disable-before-expand-snippet ()
|
|
|
|
|
"Handler for `yas-before-expand-snippet-hook'.
|
|
|
|
|
Disable smartparens and remember its initial state."
|
|
|
|
|
;; Remember the initial smartparens state only once, when expanding a top-level snippet.
|
|
|
|
|
(unless spacemacs--yasnippet-expanding
|
|
|
|
|
(setq spacemacs--yasnippet-expanding t
|
|
|
|
|
spacemacs--smartparens-enabled-initially smartparens-mode))
|
|
|
|
|
(smartparens-mode -1))
|
|
|
|
|
|
|
|
|
|
(defun spacemacs//smartparens-restore-after-exit-snippet ()
|
|
|
|
|
"Handler for `yas-after-exit-snippet-hook'.
|
|
|
|
|
Restore the initial state of smartparens."
|
|
|
|
|
(setq spacemacs--yasnippet-expanding nil)
|
|
|
|
|
(when spacemacs--smartparens-enabled-initially
|
|
|
|
|
(smartparens-mode 1)))
|