#+title: Emacs — Packages — Autocompletion #+setupfile: ../../headers #+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code #+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/autocompletion.el #+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export * Autocompletion ** Code Autocompletion Company is, in my opinion, the best autocompleting engine for Emacs, and it is one of the most popular if not /the/ most popular. #+begin_src emacs-lisp (use-package company :straight (:build t) :defer t :hook (company-mode . evil-normalize-keymaps) :init (global-company-mode) :config (setq company-minimum-prefix-length 2 company-toolsip-limit 14 company-tooltip-align-annotations t company-require-match 'never company-global-modes '(not erc-mode message-mode help-mode gud-mode) company-frontends '(company-pseudo-tooltip-frontend ; always show candidates in overlay tooltip company-echo-metadata-frontend) ; show selected candidate docs in echo area company-backends '(company-capf) company-auto-commit nil company-auto-complete-chars nil company-dabbrev-other-buffers nil company-dabbrev-ignore-case nil company-dabbrev-downcase nil)) #+end_src This package is a backend for company. It emulates ~ac-source-dictionary~ by proposing text related to the current major-mode. #+begin_src emacs-lisp (use-package company-dict :after company :straight (:build t) :config (setq company-dict-dir (expand-file-name "dicts" user-emacs-directory))) #+end_src On the other hand, ~company-box~ is a Company front-end which offers colours, icons, documentation and so on. Very nice. Declaring all the icons for the variable ~company-box-icons-all-the-icons~ is quite verbose in Elisp, so I do it with an org-table. #+name: company-box-icons | Type | Icon | Color | |---------------+--------------------------+--------| | Unknown | find_in_page | purple | | Text | text_fields | green | | Method | functions | red | | Function | functions | red | | Constructor | functions | red | | Field | functions | red | | Variable | adjust | blue | | Class | class | red | | Interface | settings_input_component | red | | Module | view_module | red | | Property | settings | red | | Unit | straighten | red | | Value | filter_1 | red | | Enum | plus_one | red | | Keyword | filter_center_focus | red | | Snippet | short_text | red | | Color | color_lens | red | | File | insert_drive_file | red | | Reference | collections_bookmark | red | | Folder | folder | red | | EnumMember | people | red | | Constant | pause_circle_filled | red | | Struct | streetview | red | | Event | event | red | | Operator | control_point | red | | TypeParameter | class | red | | Template | short_text | green | | ElispFunction | functions | red | | ElispVariable | check_circle | blue | | ElispFeature | stars | orange | | ElispFace | format_paint | pink | #+name: gen-company-box-icons #+headers: :tangle no :noweb yes :exports none :cache yes #+header: :wrap "src emacs-lisp :exports none :tangle no" #+begin_src emacs-lisp :var table=company-box-icons (mapconcat (lambda (row) (format "(%s . ,(all-the-icons-material \"%s\" :face 'all-the-icons-%s))" (car row) (cadr row) (caddr row))) table "\n") #+end_src #+RESULTS[8ebf4bb3f7f354571a5d42cf58f8b9ba847ba028]: gen-company-box-icons #+begin_src emacs-lisp :exports none :tangle no (Unknown . ,(all-the-icons-material "find_in_page" :face 'all-the-icons-purple)) (Text . ,(all-the-icons-material "text_fields" :face 'all-the-icons-green)) (Method . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) (Function . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) (Constructor . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) (Field . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) (Variable . ,(all-the-icons-material "adjust" :face 'all-the-icons-blue)) (Class . ,(all-the-icons-material "class" :face 'all-the-icons-red)) (Interface . ,(all-the-icons-material "settings_input_component" :face 'all-the-icons-red)) (Module . ,(all-the-icons-material "view_module" :face 'all-the-icons-red)) (Property . ,(all-the-icons-material "settings" :face 'all-the-icons-red)) (Unit . ,(all-the-icons-material "straighten" :face 'all-the-icons-red)) (Value . ,(all-the-icons-material "filter_1" :face 'all-the-icons-red)) (Enum . ,(all-the-icons-material "plus_one" :face 'all-the-icons-red)) (Keyword . ,(all-the-icons-material "filter_center_focus" :face 'all-the-icons-red)) (Snippet . ,(all-the-icons-material "short_text" :face 'all-the-icons-red)) (Color . ,(all-the-icons-material "color_lens" :face 'all-the-icons-red)) (File . ,(all-the-icons-material "insert_drive_file" :face 'all-the-icons-red)) (Reference . ,(all-the-icons-material "collections_bookmark" :face 'all-the-icons-red)) (Folder . ,(all-the-icons-material "folder" :face 'all-the-icons-red)) (EnumMember . ,(all-the-icons-material "people" :face 'all-the-icons-red)) (Constant . ,(all-the-icons-material "pause_circle_filled" :face 'all-the-icons-red)) (Struct . ,(all-the-icons-material "streetview" :face 'all-the-icons-red)) (Event . ,(all-the-icons-material "event" :face 'all-the-icons-red)) (Operator . ,(all-the-icons-material "control_point" :face 'all-the-icons-red)) (TypeParameter . ,(all-the-icons-material "class" :face 'all-the-icons-red)) (Template . ,(all-the-icons-material "short_text" :face 'all-the-icons-green)) (ElispFunction . ,(all-the-icons-material "functions" :face 'all-the-icons-red)) (ElispVariable . ,(all-the-icons-material "check_circle" :face 'all-the-icons-blue)) (ElispFeature . ,(all-the-icons-material "stars" :face 'all-the-icons-orange)) (ElispFace . ,(all-the-icons-material "format_paint" :face 'all-the-icons-pink)) #+end_src #+begin_src emacs-lisp (use-package company-box :straight (:build t) :after (company all-the-icons) :config (setq company-box-show-single-candidate t company-box-backends-colors nil company-box-max-candidates 50 company-box-icons-alist 'company-box-icons-all-the-icons company-box-icons-all-the-icons (let ((all-the-icons-scale-factor 0.8)) `( <>)))) #+end_src ** Ivy My main menu package is =ivy= which I use as much as possible –I’ve noticed =helm= can be slow, very slow in comparison to =ivy=, so I’ll use the latter as much as possible. Actually, only =ivy= is installed for now. I could have used =ido= too, but I find it to be a bit too restricted in terms of features compared to =ivy=. #+begin_src emacs-lisp (use-package ivy :straight t :defer t :diminish :bind (("C-s" . swiper) :map ivy-minibuffer-map ("TAB" . ivy-alt-done) ("C-l" . ivy-alt-done) ("C-t" . ivy-next-line) ("C-s" . ivy-previous-line) ("C-u" . ivy-scroll-up-command) ("C-d" . ivy-scroll-down-command) :map ivy-switch-buffer-map ("C-t" . ivy-next-line) ("C-s" . ivy-previous-line) ("C-l" . ivy-done) ("C-d" . ivy-switch-buffer-kill) :map ivy-reverse-i-search-map ("C-t" . ivy-next-line) ("C-s" . ivy-previous-line) ("C-d" . ivy-reverse-i-search-kill)) :config (ivy-mode 1) (setq ivy-wrap t ivy-height 17 ivy-sort-max-size 50000 ivy-fixed-height-minibuffer t ivy-read-action-functions #'ivy-hydra-read-action ivy-read-action-format-function #'ivy-read-action-format-columns projectile-completion-system 'ivy ivy-on-del-error-function #'ignore ivy-use-selectable-prompt t)) #+end_src There is also [[https://github.com/raxod502/prescient.el][~prescient.el~]] that offers some nice features when coupled with ~ivy~, guess what was born out of it? ~ivy-prescient~, of course! #+begin_src emacs-lisp (use-package ivy-prescient :after ivy :straight (:build t)) #+end_src I warned you I’d use too much ~all-the-icons~, I did! #+begin_src emacs-lisp (use-package all-the-icons-ivy :straight (:build t) :after (ivy all-the-icons) :init (all-the-icons-ivy-setup) :hook (after-init . all-the-icons-ivy-setup)) (all-the-icons-ivy-setup) #+end_src A buffer popping at the bottom of the screen is nice and all, but have you considered a floating buffer in the centre of your frame? #+begin_src emacs-lisp (use-package ivy-posframe :defer t :after (:any ivy helpful) :hook (ivy-mode . ivy-posframe-mode) :straight (:build t) :init (ivy-posframe-mode 1) :config (setq ivy-fixed-height-minibuffer nil ivy-posframe-border-width 10 ivy-posframe-parameters `((min-width . 90) (min-height . ,ivy-height)))) #+end_src Something that can be missing sometimes in Ivy is the ability to select multiple entries at once. For instance, when programming in Java, LPS can offer you to automatically generate the methods ~equals~ and ~hashCode~ based on selected members, but with vanilla Ivy, you can only select one. Not really useful. ~ivy-hydra~ is a package that offers a Hydra interface when in Ivy which allows you to select multiple choices among other things. #+begin_src emacs-lisp (use-package ivy-hydra :requires (ivy hydra) :after ivy :straight (:build t)) #+end_src Finally, let’s make ~ivy~ richer: #+begin_src emacs-lisp (use-package ivy-rich :straight (:build t) :after ivy :init (ivy-rich-mode 1)) #+end_src ** Counsel I could almost merge this chapter with the previous one since counsel is a package that provides loads of completion functions for ivy. The ones I find most useful are ~counsel-M-x~ and ~counsel-find-file~. #+begin_src emacs-lisp (use-package counsel :straight t :after recentf :after ivy :bind (("M-x" . counsel-M-x) ("C-x b" . counsel-ibuffer) ("C-x C-f" . counsel-find-file) :map minibuffer-local-map ("C-r" . 'counsel-minibuffer-history))) #+end_src ** Yasnippet Yasnippet allows you to insert some pre-made code by just typing a few characters. It can even generate some string with Elisp expressions and ask the user for some input in some precise places. #+begin_src emacs-lisp (use-package yasnippet :defer t :straight (:build t) :init (yas-global-mode) :hook ((prog-mode . yas-minor-mode) (text-mode . yas-minor-mode))) #+end_src Of course, yasnippet wouldn’t be as awesome as it is without pre-made snippets. #+begin_src emacs-lisp (use-package yasnippet-snippets :defer t :after yasnippet :straight (:build t)) #+end_src Similarly, yatemplate offers pre-made files rather than just strings. That’s still yasnippet by the way. #+begin_src emacs-lisp (use-package yatemplate :defer t :after yasnippet :straight (:build t)) #+end_src And finally, with ivy you can choose your snippets from a menu if you’re not sure or if you don’t remember what your snippet is. #+begin_src emacs-lisp (use-package ivy-yasnippet :defer t :after (ivy yasnippet) :straight (:build t)) #+end_src