config.phundrak.com/docs/emacs/packages/autocompletion.org
Lucien Cartier-Tilet 788ecefbe5
docs(emacs): move most keybindings to same file
All general keybindings (not linked to a specific mode) are now
defined in keybindings.org in neatly displayed tables.
2024-04-03 06:07:58 +02:00

12 KiB
Raw Permalink Blame History

Emacs — Packages — Autocompletion

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.

(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))

This package is a backend for company. It emulates ac-source-dictionary by proposing text related to the current major-mode.

(use-package company-dict
  :after company
  :straight (:build t)
  :config
  (setq company-dict-dir (expand-file-name "dicts" user-emacs-directory)))

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.

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
(mapconcat (lambda (row)
             (format "(%s . ,(all-the-icons-material \"%s\" :face 'all-the-icons-%s))"
                     (car row)
                     (cadr row)
                     (caddr row)))
           table
           "\n")
(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))
          `(
            <<gen-company-box-icons()>>))))

Ivy

My main menu package is ivy which I use as much as possible Ive noticed helm can be slow, very slow in comparison to ivy, so Ill 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.

(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))

There is also prescient.el that offers some nice features when coupled with ivy, guess what was born out of it? ivy-prescient, of course!

(use-package ivy-prescient
  :after ivy
  :straight (:build t))

I warned you Id use too much all-the-icons, I did!

(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)

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?

(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))))

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.

(use-package ivy-hydra
  :requires (ivy hydra)
  :after ivy
  :straight (:build t))

Finally, lets make ivy richer:

(use-package ivy-rich
  :straight (:build t)
  :after ivy
  :init
  (ivy-rich-mode 1))

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.

(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)))

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.

(use-package yasnippet
  :defer t
  :straight (:build t)
  :init
  (yas-global-mode)
  :hook ((prog-mode . yas-minor-mode)
         (text-mode . yas-minor-mode)))

Of course, yasnippet wouldnt be as awesome as it is without pre-made snippets.

(use-package yasnippet-snippets
  :defer t
  :after yasnippet
  :straight (:build t))

Similarly, yatemplate offers pre-made files rather than just strings. Thats still yasnippet by the way.

(use-package yatemplate
  :defer t
  :after yasnippet
  :straight (:build t))

And finally, with ivy you can choose your snippets from a menu if youre not sure or if you dont remember what your snippet is.

(use-package ivy-yasnippet
  :defer t
  :after (ivy yasnippet)
  :straight (:build t))