How is snippet expansion/code completion supposed to work in Emacs with eglot/elixir-ls

I’ve got elixir-mode and eglot configured in my emacs.d and it mostly works. One thing I can’t figure out though is how to work with the code completion (via company) in elixir code.

Say I type defm at this point I get the completion options pop up. I select defmodule and then it expands to

defmodule $1 do $0 end 

But the cursor (point) moves to the end of end. I get no opportunity to specify the module name and also complete the module body.

When I disable eglot and use only elixir-mode I get the expected behaviour were selecting defmodule from the completion list places the cursor (point) between defmodule and do where I type the module name then another tab places the cursor inside the module body.

What is the way to work with what seems to be eglot’s way of code completion?

@Pilgrim I couldn’t reproduce this bug. Running latest eglot in elpa, and elixir-lsp/elixir-ls (more updated fork at the moment). When I hit enter on defmodule completion, works as expected: cursor at module name, and tab goes to module body.

I wonder if you have a company issue, or with another package.

@rodrigues can I take a look around your emacs.d? My company config is really simple below and I spent hours going over it without success.

;; Company mode (add-to-list 'completion-styles 'initials t) (use-package company :ensure t :hook (after-init . global-company-mode) :init (setq company-minimum-prefix-length 2) ;;(setq company-auto-complete nil) (setq company-idle-delay 0) (setq company-require-match 'never) (setq-default company-dabbrev-other-buffers 'all company-tooltip-align-annotations t) (setq tab-always-indent 'complete) ;;(defvar completion-at-point-functions-saved nil) :config (define-key company-mode-map (kbd "M-/") 'company-complete) (define-key company-active-map (kbd "C-n") 'company-select-next) (define-key company-active-map (kbd "C-p") 'company-select-previous)) 

Eglot currently is setup like so

(use-package eglot :ensure t) 

and Elixir’s looks like this:

(use-package elixir-mode :after (company flycheck) :ensure t :init ;;(add-to-list 'exec-path "/Users/napo/Github/elixir-ls/release") (add-to-list 'eglot-server-programs '(elixir-mode . ("/Users/napo/Github/elixir-ls/release/language_server.sh"))) ;;(add-hook 'elixir-mode-hook #'lsp) (add-hook 'elixir-mode-hook 'eglot-ensure) (add-hook 'elixir-mode-hook 'flycheck-mode) (add-hook 'elixir-mode-hook #'smartparens-mode) (add-hook 'elixir-mode-hook (lambda () (add-hook 'before-save-hook 'eglot-format nil t)))) 
1 Like

@Pilgrim my emacs.d repo gets constantly rebased with https://github.com/purcell/emacs.d

Other than that, that’s my only company specific custom config:

(add-hook 'after-init-hook 'global-company-mode) (setq company-dabbrev-downcase 0) (setq company-idle-delay 0) 

As for eglot/elixir, there it is, at the moment:

(require-package 'elixir-mode) (require-package 'eglot) (require 'eglot) (require 'eldoc-box) (add-to-list 'eglot-server-programs '(elixir-mode . ("sh" "/Users/rodrigues/code/elixir-ls/release/language_server.sh"))) (add-hook 'elixir-mode-hook (lambda () (subword-mode) (eglot-ensure) (company-mode) (flymake-mode) (add-hook 'before-save-hook 'eglot-format nil t))) 
1 Like

I run into same issue with my Emacs setup, and I was able to solve it.

Based on the github issue I was able to deduce that Eglot upon start communicates to Language Server that he supports snippets, and I would guess, that based on this start-up info it will either try to pass it into snippet engine or not. You could look into your *EGLOT (....) events* buffer; find first message ( with M-<), and verify your settings.

client-request (id:1) Fri Jan 31 00:35:47 2020: (:jsonrpc "2.0" :id 1 :method "initialize" :params (:processId 14783 :rootPath .... (:workspace ...... (:dynamicRegistration :json-false :completionItem (:snippetSupport t) :contextSupport t) 

I was able to achieve such setup by installing Yasnippets, and turning them on in elixir-mode

 (use-package elixir-mode) (use-package eglot :commands (eglot eglot-ensures) :hook (elixir-mode . eglot-ensure) (before-save . eglot-format-buffer) :config (add-to-list `eglot-server-programs `(elixir-mode ,(expand-file-name "~/elixir_ls/release/language_server.sh")))) (use-package yasnippet :hook (elixir-mode . yas-minor-mode)) 
4 Likes