Doom-emacs: Cider + Company not working as it should

Created on 18 Apr 2019  ·  13Comments  ·  Source: hlissner/doom-emacs

Observed behavior

Similar to issue #903, however instead of Intero I am having this problem with Cider.

Basically after opening a Cider REPL, C-j or C-k doesn't work as it should in Company (so instead of selecting next/previous Company suggestion, it simply does something else like C-j inserting a new line).

Expected behavior

C-j - company-select-next
C-k - company-select-previous
as in the bindings.el

Steps to reproduce

  1. Open a Clojure project and start a Cider REPL with SPC m '
  2. Type something, call auto-complete and try to use C-j or C-k

System information


Click to expand

  • OS: gnu/linux (x86_64-pc-linux-gnu)
  • Emacs: 26.1 (abr 08, 2019)
  • Doom: 2.0.9 (HEAD -> develop, origin/develop 6afc8e55 2019-04-17 18:38:02 -0400)
  • Graphic display: t (daemon: nil)
  • System features: XPM JPEG TIFF GIF PNG RSVG SOUND DBUS GSETTINGS NOTIFY LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT LIBOTF XFT ZLIB TOOLKIT_SCROLL_BARS GTK3 X11 MODULES THREADS LIBSYSTEMD
  • Details:
    elisp env bootstrapper: nil elc count: 0 uname -a: Linux 5.0.7 #1-NixOS SMP Fri Apr 5 20:34:54 UTC 2019 x86_64 modules: (:feature eval (evil +everywhere) file-templates (lookup +docsets) snippets workspaces :completion company (ivy +fuzzy) :ui doom doom-dashboard evil-goggles hl-todo indent-guides modeline nav-flash neotree (popup +all +defaults) vc-gutter vi-tilde-fringe window-select :editor fold (format +onsave) multiple-cursors rotate-text :emacs dired electric eshell imenu term vc :tools ansible docker editorconfig flycheck magit make rgb terraform :lang cc clojure data elixir emacs-lisp hy javascript markdown nix (org +attach +babel +capture +export +present) python ruby (sh +zsh) web :config default) packages: (company-emoji evil-collection evil-lisp-state flymd lispyville sort-words uuidgen xterm-color (frame-fns :recipe (frame-fns :fetcher github :repo emacsmirror/frame-fns)) (frame-cmds :recipe (frame-cmds :fetcher github :repo emacsmirror/frame-cmds)) (zoom-frm :recipe (zoom-frm :fetcher github :repo emacsmirror/zoom-frm))) exec-path: (~/.emacs.d/bin ~/.local/bin /nix/store/xf59s14j0x8l34agxiq6n1rn54wia3b1-kitty-0.13.3/bin /nix/store/4y5lv3a8s42wd0w0wga9sfflf6x0s5wg-imagemagick-6.9.9-34/bin /nix/store/k1gmlgblqqywmnzqxzlm0a2473r14zx5-xsel-unstable-2018-01-10/bin ~/bin /run/wrappers/bin ~/.nix-profile/bin /nix/var/nix/profiles/default/bin /run/current-system/sw/bin /etc/profiles/per-user/thiagoko/bin /nix/store/z6x936aa6kfnwpz8fb34z28qng5prrp9-emacs-26.1/libexec/emacs/26.1/x86_64-pc-linux-gnu)
:completion company :lang clojure bug keybinds resolved

Most helpful comment

A more complete example of the workaround form those who need it:

(after! cider
  (add-hook 'company-completion-started-hook 'custom/set-company-maps)
  (add-hook 'company-completion-finished-hook 'custom/unset-company-maps)
  (add-hook 'company-completion-cancelled-hook 'custom/unset-company-maps))

(defun custom/unset-company-maps (&rest unused)
  "Set default mappings (outside of company).
    Arguments (UNUSED) are ignored."
  (general-def
    :states 'insert
    :keymaps 'override
    "<down>" nil
    "<up>"   nil
    "RET"    nil
    [return] nil
    "C-n"    nil
    "C-p"    nil
    "C-j"    nil
    "C-k"    nil
    "C-h"    nil
    "C-u"    nil
    "C-d"    nil
    "C-s"    nil
    "C-S-s"   (cond ((featurep! :completion helm) nil)
                    ((featurep! :completion ivy)  nil))
    "C-SPC"   nil
    "TAB"     nil
    [tab]     nil
    [backtab] nil))

(defun custom/set-company-maps (&rest unused)
  "Set maps for when you're inside company completion.
    Arguments (UNUSED) are ignored."
  (general-def
    :states 'insert
    :keymaps 'override
    "<down>" #'company-select-next
    "<up>" #'company-select-previous
    "RET" #'company-complete
    [return] #'company-complete
    "C-w"     nil  ; don't interfere with `evil-delete-backward-word'
    "C-n"     #'company-select-next
    "C-p"     #'company-select-previous
    "C-j"     #'company-select-next
    "C-k"     #'company-select-previous
    "C-h"     #'company-show-doc-buffer
    "C-u"     #'company-previous-page
    "C-d"     #'company-next-page
    "C-s"     #'company-filter-candidates
    "C-S-s"   (cond ((featurep! :completion helm) #'helm-company)
                    ((featurep! :completion ivy)  #'counsel-company))
    "C-SPC"   #'company-complete-common
    "TAB"     #'company-complete-common-or-cycle
    [tab]     #'company-complete-common-or-cycle
    [backtab] #'company-select-previous    ))

All 13 comments

Did you figure out the issue?

No, it is just that I don't use Company that way anymore.

I can reopen this issue if you want to track.

@thiagokokada can you reopen this, think this is a valid issue. Also @hlissner, could this be the culprit? Cider seems to be redefining some of company bindings doom defines. I added the following hook and the autocomplete bindings seem to be fixed as a result, not sure about cider-repl implications of redefining these keys.

# Rebinds C-j and C-k for company completions in clojure buffers with cider enabled
(add-hook! (cider-mode)
  (map! :i "C-j" #'company-select-next-or-abort)
  (map! :i "C-k" #'company-select-pervious-or-abort))

@sunyaa No, because cider-start-map is bound to C-c C-x, so that keymap won't be active otherwise.

Your snippet has the nasty side effect of changing C-j and C-k globally. i.e. in all buffers opened after your first clojure buffer, whether or not they are clojure buffers.

It's more likely that one of evil-collection-cider's C-j/C-k keybinds are shadowing company's.

@sunyaa Another possibility: evil hasn't had an opportunity to normalize its keymaps after cider-mode as activated. This is a known issue with evil keybinds on minor mode maps.

You could give this a try:

(add-hook 'cider-repl-mode-hook #'evil-normalize-keymaps)

Or replace cider-repl-mode-hook with one of the other cider modes. cider-mode-hook is already covered by evil-collection-cider.

Another thing to try: Move :editor evil above :completion company in your doom! blocks (in ~/.doom.d/init.el). Don't forget to run doom sync afterwards.

Let me know if that works!

Another thing to try: Move :editor evil above :completion company in your doom! blocks (in ~/.doom.d/init.el). Don't forget to run doom sync afterwards.

Did not work.

You could give this a try:

(add-hook 'cider-repl-mode-hook #'evil-normalize-keymaps)

Neither this one.

This workaround worked for the arrow keys, however C-j and C-k still have erratic behavior:
https://github.com/hlissner/doom-emacs/issues/2610#issuecomment-593067367

Fully workaround I think:

(after! cider
  (add-hook 'company-completion-started-hook 'ans/set-company-maps)
  (add-hook 'company-completion-finished-hook 'ans/unset-company-maps)
  (add-hook 'company-completion-cancelled-hook 'ans/unset-company-maps)

  (defun ans/unset-company-maps (&rest unused)
    "Set default mappings (outside of company).
    Arguments (UNUSED) are ignored."
    (general-def
      :states 'insert
      :keymaps 'override
      "<up>" nil
      "<down>" nil
      "C-j" nil
      "C-k" nil
      "RET" nil
      [return] nil))

  (defun ans/set-company-maps (&rest unused)
    "Set maps for when you're inside company completion.
    Arguments (UNUSED) are ignored."
    (general-def
      :states 'insert
      :keymaps 'override
      "<down>" 'company-select-next
      "<up>" 'company-select-previous
      "C-j" 'company-select-next
      "C-k" 'company-select-previous
      "RET" 'company-complete
      [return] 'company-complete)))

So I tried this again:

(add-hook! cider-repl-mode #'evil-normalize-keymaps)

And it worked :smile: .

I don't know if the fact that I recently cleaned up my Emacs configuration helped, or it is the packages that I updated, or maybe I simply set it wrong before. But it is working now.

Maybe we can add this to clojure module?

A more complete example of the workaround form those who need it:

(after! cider
  (add-hook 'company-completion-started-hook 'custom/set-company-maps)
  (add-hook 'company-completion-finished-hook 'custom/unset-company-maps)
  (add-hook 'company-completion-cancelled-hook 'custom/unset-company-maps))

(defun custom/unset-company-maps (&rest unused)
  "Set default mappings (outside of company).
    Arguments (UNUSED) are ignored."
  (general-def
    :states 'insert
    :keymaps 'override
    "<down>" nil
    "<up>"   nil
    "RET"    nil
    [return] nil
    "C-n"    nil
    "C-p"    nil
    "C-j"    nil
    "C-k"    nil
    "C-h"    nil
    "C-u"    nil
    "C-d"    nil
    "C-s"    nil
    "C-S-s"   (cond ((featurep! :completion helm) nil)
                    ((featurep! :completion ivy)  nil))
    "C-SPC"   nil
    "TAB"     nil
    [tab]     nil
    [backtab] nil))

(defun custom/set-company-maps (&rest unused)
  "Set maps for when you're inside company completion.
    Arguments (UNUSED) are ignored."
  (general-def
    :states 'insert
    :keymaps 'override
    "<down>" #'company-select-next
    "<up>" #'company-select-previous
    "RET" #'company-complete
    [return] #'company-complete
    "C-w"     nil  ; don't interfere with `evil-delete-backward-word'
    "C-n"     #'company-select-next
    "C-p"     #'company-select-previous
    "C-j"     #'company-select-next
    "C-k"     #'company-select-previous
    "C-h"     #'company-show-doc-buffer
    "C-u"     #'company-previous-page
    "C-d"     #'company-next-page
    "C-s"     #'company-filter-candidates
    "C-S-s"   (cond ((featurep! :completion helm) #'helm-company)
                    ((featurep! :completion ivy)  #'counsel-company))
    "C-SPC"   #'company-complete-common
    "TAB"     #'company-complete-common-or-cycle
    [tab]     #'company-complete-common-or-cycle
    [backtab] #'company-select-previous    ))

The reason why this issue appeared is described in clojure-emacs/cider#2908.

The workaround given by madhat2r has some disadvantages:

  1. The key bindings of company-serach-map won't work.
  2. You may need to duplicate the definition of key bindings twice (especially if you define your own key bindings inside
    company-active-map and company-search-map).

As an alternative workaround:

(with-eval-after-load 'company
  (add-hook 'evil-local-mode-hook
            (lambda ()
              ;; Note:
              ;; Check if `company-emulation-alist' is in
              ;; `emulation-mode-map-alists', if true, call
              ;; `company-ensure-emulation-alist' to ensure
              ;; `company-emulation-alist' is the first item of
              ;; `emulation-mode-map-alists', thus has a higher
              ;; priority than keymaps of evil-mode.
              ;; We raise the priority of company-mode keymaps
              ;; unconditionally even when completion is not
              ;; activated. This should not cause problems,
              ;; because when completion is activated, the value of
              ;; `company-emulation-alist' is ((t . company-my-keymap)),
              ;; when completion is not activated, the value is ((t . nil)).
              (when (memq 'company-emulation-alist emulation-mode-map-alists)
                (company-ensure-emulation-alist)))))

If you are curious about why this workaround works, see clojure-emacs/cider#2908.

As of 2e476de this issue should be resolved. Let me know if that isn't the case and I'll reopen it. Thanks for bringing it to my attention!

@CloseToZero Thank you for shedding light on this.

Was this page helpful?
0 / 5 - 0 ratings