;;; completion.el --- Configures automatic code completion -*- lexical-binding: t; -*- ;;; Commentary: ;;; Code: (eval-when-compile (require 'cl)) (defun user--company-mode-hook () "Company mode hook." (message "user--company-mode-hook") (when (derived-mode-p 'prog-mode) (define-key (current-local-map) (user/get-key :code :complete) 'company-indent-or-complete-common)) ;; ;; (user/complete-at-point-install) ;; ;;; (Bindings) ;;; ;; ;; (when (current-local-map) ;; ;; (define-key (current-local-map) (user/get-key :code :auto-complete) 'company-complete)) ;; (when (current-local-map) ;; (define-key (current-local-map) (user/get-key :code :complete) 'company-complete)) ;; (when (current-local-map) ;; (define-key (current-local-map) (user/get-key :code :complete) 'company-indent-or-complete-common)) ) (defun user/company-mode-p () "True if auto-complete should be used." (and (boundp 'global-company-mode) global-company-mode)) ;; (defun user/complete-at-point-install () ;; "Install completion backend in complete-at-point." ;; (setq ;; ;; Insert completion backend into `completion-at-point'. ;; completion-at-point-functions ;; (cons 'user/complete-at-point ;; (remove 'user/complete-at-point completion-at-point-functions)))) ;; (defun user/company-check-expansion () ;; "Check if expression can be expanded by company." ;; (save-excursion ;; (if (looking-at "\\_>") t ;; (backward-char 1) ;; (if (looking-at "\\.") t ;; (backward-char 1) ;; (if (looking-at "->") t nil))))) ;; (defun user/complete-at-point () ;; "Complete thing at point using completion backend." ;; (cond ;; ((minibufferp) (minibuffer-complete)) ;; ;; ((and (boundp 'auto-complete-mode) auto-complete-mode) #'auto-complete) ;; ((and (boundp 'company-mode) company-mode (user/company-check-expansion)) #'company-complete-common) ;; (t #'indent-for-tab-command))) ;; (defun ac-pcomplete () ;; "Auto-complete source for pcomplete." ;; ;; eshell uses `insert-and-inherit' to insert a \t if no completion ;; ;; can be found, but this must not happen as auto-complete source ;; (cl-flet ((insert-and-inherit (&rest args))) ;; ;; this code is stolen from `pcomplete' in pcomplete.el ;; (let* (tramp-mode ;; do not automatically complete remote stuff ;; (pcomplete-stub) ;; (pcomplete-show-list t) ;; inhibit patterns like * being deleted ;; pcomplete-seen pcomplete-norm-func ;; pcomplete-args pcomplete-last pcomplete-index ;; (pcomplete-autolist pcomplete-autolist) ;; (pcomplete-suffix-list pcomplete-suffix-list) ;; (candidates (pcomplete-completions)) ;; (beg (pcomplete-begin)) ;; ;; note, buffer text and completion argument may be ;; ;; different because the buffer text may bet transformed ;; ;; before being completed (e.g. variables like $HOME may be ;; ;; expanded) ;; (buftext (buffer-substring beg (point))) ;; (arg (nth pcomplete-index pcomplete-args))) ;; ;; we auto-complete only if the stub is non-empty and matches ;; ;; the end of the buffer text ;; (when (and (not (zerop (length pcomplete-stub))) ;; (or (string= pcomplete-stub ; Emacs 23 ;; (substring buftext ;; (max 0 ;; (- (length buftext) ;; (length pcomplete-stub))))) ;; (string= pcomplete-stub ; Emacs 24 ;; (substring arg ;; (max 0 ;; (- (length arg) ;; (length pcomplete-stub))))))) ;; ;; Collect all possible completions for the stub. Note that ;; ;; `candidates` may be a function, that's why we use ;; ;; `all-completions`. ;; (let* ((cnds (all-completions pcomplete-stub candidates)) ;; (bnds (completion-boundaries pcomplete-stub ;; candidates ;; nil ;; "")) ;; (skip (- (length pcomplete-stub) (car bnds)))) ;; ;; We replace the stub at the beginning of each candidate by ;; ;; the real buffer content. ;; (mapcar #'(lambda (cand) (concat buftext (substring cand skip))) ;; cnds)))))) ;; (defvar ac-source-pcomplete ;; '((candidates . ac-pcomplete))) ;; (defun add-ac-sources (&rest sources) ;; "Add SOURCES for auto-complete after it has been loaded." ;; (when (user/auto-complete-p) ;; (dolist (source sources) ;; (if (boundp 'ac-sources) ;; (add-to-list 'ac-sources source) ;; (error "Declaration of ac-sources is missing!"))))) ;; (defun add-ac-modes (&rest major-modes) ;; "Add MAJOR-MODES for auto-complete after it has been loaded." ;; (when (user/auto-complete-p) ;; (dolist (mode major-modes) ;; (if (boundp 'ac-modes) ;; (add-to-list 'ac-modes mode) ;; (error "Declaration of ac-modes is missing!"))))) ;; (defun company-complete-common-or-selection () ;; "Insert the common part of all candidates, or the selection." ;; (interactive) ;; (when (company-manual-begin) ;; (let ((tick (buffer-chars-modified-tick))) ;; (call-interactively 'company-complete-common) ;; (when (eq tick (buffer-chars-modified-tick)) ;; (let ((company-selection-wrap-around t)) ;; (call-interactively 'company-complete-selection)))))) ;; (defun add-company-sources (&rest sources) ;; "Add SOURCES for company completion in current mode, if it has been loaded." ;; (when (user/company-mode-p) ;; (when (boundp 'company-backends) ;; (setq-local ;; company-backends ;; (append sources company-backends))))) (defun user--completion-config () "Initialize automatic code completion." (setq ;; Activate completion on tab. tab-always-indent 'complete ;; Cycle completions in minibuffer below a certain threshold. completion-cycle-threshold 5) ;; Allow completion of acronyms and initialisms. (add-to-list 'completion-styles 'initials t) ;;; (Packages) ;;; ;; (use-package auto-complete ;; :disabled ;; :requires popup fuzzy ;; :defer ;; :quelpa (auto-complete ;; :fetcher github ;; :repo "auto-complete/auto-complete") ;; :diminish auto-complete-mode ;; :init ;; (add-hook 'flymake-mode-hook 'ac-flyspell-workaround) ;; (add-hook 'auto-complete-mode-hook 'user--auto-complete-mode-hook) ;; :config ;; (with-feature 'auto-complete-config ;; ;; Load default configuration. ;; (ac-config-default) ;; ;; Don't forcibly enable auto-complete. ;; (global-auto-complete-mode -1)) ;; (validate-setq ;; ;; Limit the number of candidates. ;; ac-candidate-limit 40 ;; ;; Delay until narrowing completions. ;; ac-delay 0.5 ;; ;; Do not trigger completion automatically. ;; ac-auto-start nil ;; ;; Use fuzzy matching. ;; ac-fuzzy-enable t ;; ac-use-fuzzy t ;; ;; Do not pop up menu automatically. ;; ac-auto-show-menu nil ;; ;; Allow normal navigation keys in menu. ;; ac-use-menu-map t ;; ;; Do not auto-expand common candidates. ;; ac-expand-on-auto-complete nil ;; ;; Show quick help popup after half a second. ;; ac-use-quick-help t ;; ac-quick-help-delay 0.5 ;; ;; Store the completion history in the cache directory. ;; ac-comphist-file (path-join *user-cache-directory* "ac-comphist.dat")) ;; ;; Set up auto-complete for lisp-interaction- and ielm-mode. ;; (dolist (hook (list 'lisp-interaction-mode-hook ;; 'ielm-mode-hook)) ;; (add-hook hook 'ac-emacs-lisp-mode-setup)) ;; ;;; (Bindings) ;;; ;; (ac-set-trigger-key (user/get-key :code :try-complete)) ;; (validate-setq ;; ac-completing-map ;; (let ((map (make-sparse-keymap))) ;; ;; Expand on tab. ;; (define-key map (user/get-key :code :try-complete) 'ac-expand-common) ;; ;; Complete on enter. ;; (define-key map (user/get-key :code :complete) 'ac-complete) ;; ;; Bind configured auto complete key. ;; (define-key map (user/get-key :code :auto-complete) 'auto-complete) ;; ;; Scroll quick-help using M-n/p. ;; (define-key map (kbd "C-M-n") 'ac-quick-help-scroll-down) ;; (define-key map (kbd "C-M-p") 'ac-quick-help-scroll-up) ;; map))) (use-package company :diminish company-mode :hook (company-mode-hook . user--company-mode-hook) :config (validate-setq ;; Do not trigger completion automatically. ;; company-idle-delay nil ;; Complete immediately. company-minimum-prefix-length 0 ;; Show commonly used matches first. company-transformers '(company-sort-by-occurrence) ;; Align annotations to the right of tooltip. company-tooltip-align-annotations t ;; Active company frontends. ;; company-frontends ;; '(company-pseudo-tooltip-unless-just-one-frontend ;; company-preview-frontend ;; company-echo-metadata-frontend) ) ;; (define-key company-active-map (user/get-key :code :complete) 'company-complete-selection) ;; (define-key company-active-map ;; (user/get-key :code :try-complete) 'company-complete-common-or-selection) ;; (define-key company-active-map ;; (user/get-key :basic :forward-line) 'company-select-next) ;; (define-key company-active-map ;; (user/get-key :basic :backward-line) 'company-select-previous) ;; (define-key company-active-map (user/get-key :code :complete) 'company-search-candidates) (use-package company-dabbrev-code :ensure company :config (validate-setq ;; Complete even outside of code. company-dabbrev-code-everywhere t)) (use-package company-flx :after (company) :config (company-flx-mode t)) (use-package company-quickhelp :if window-system :after (company) :hook (company-mode-hook . company-quickhelp-mode) :config (validate-setq ;; Show quick help popup after half a second. company-quickhelp-delay 0.5)) (use-package company-box :if (display-graphic-p) :hook (company-mode . company-box-mode)) (global-company-mode t))) (user--completion-config) (provide 'ux/completion) ;;; completion.el ends here