2

I have put the following code (partially adapted from a company-mode issue and a Stack Exchange question) in my init.el in order to adjust the keybindings active in the company-mode completions menu:

(defun company-complete-if-explicit ()
  "Complete the current selection, but only if the user has interacted
explicitly with Company."
  (interactive)
  (if (company-explicit-action-p)
      (company-complete)
    (call-interactively
     (key-binding (this-command-keys)))))

(define-key company-active-map (kbd "<return>") #'company-complete-if-explicit)
(define-key company-active-map (kbd "RET") #'company-complete-if-explicit)
(define-key company-active-map (kbd "TAB") #'company-complete-selection)
(define-key company-active-map (kbd "SPC") nil)

(setq company-auto-complete-chars nil)

In terminal Emacs, pressing RET will dismiss the completions menu and insert a newline. However, if I have explicitly interacted with the menu (for instance, using up and down), then RET will instead insert the selected completion.

The problem is that this doesn't work in windowed Emacs: if I press <return> while the completions menu is showing (but I haven't explicitly interacted with it), then instead of Emacs inserting a newline, I receive the following error:

Debugger entered--Lisp error: (wrong-type-argument commandp nil)
  call-interactively(nil)
  (if (company-explicit-action-p) (company-complete) (call-interactively (key-binding (this-command-keys))))
  company-complete-if-explicit()
  call-interactively(company-complete-if-explicit nil nil)
  command-execute(company-complete-if-explicit)

I debugged this, and here is what I think is happening:

  • In windowed Emacs, the Return key sends <return> instead of RET.
  • Only RET has a binding (to newline), but normally <return> is translated automatically to RET, so the Return key still inserts a newline in windowed Emacs.
  • When I call this-command-keys in company-complete-if-explicit, the returned value is <return>.
  • The key-binding function does not appear to do the key translation that usually occurs, so that (key-binding (kbd "RET")) is newline but (key-binding (kbd "<return>")) is nil.
  • The error is thrown because nil is then passed to call-interactively.

My question is therefore: what is the best way to fix this problem (either by making key-binding perform automatic translations, or otherwise)?

  • 1
    I don't have time to write up a full answer at the moment, but if I read your intent correctly, this seems to be quite relevant. – PythonNut Sep 30 '16 at 0:21
  • @PythonNut It's beautiful and perfect! The patch is at: github.com/raxod502/radian/commit/… I will add an answer summarizing it, unless you would like to add your own answer. – Radon Rosborough Sep 30 '16 at 2:02
1

The solution that worked for me was to replace

(defun company-complete-if-explicit ()
  "Complete the current selection, but only if the user has interacted
explicitly with Company."
  (interactive)
  (if (company-explicit-action-p)
      (company-complete)
    (call-interactively
     (key-binding (this-command-keys)))))

;; <return> is for windowed Emacs; RET is for terminal Emacs
(define-key company-active-map (kbd "<return>") #'company-complete-if-explicit)
(define-key company-active-map (kbd "RET") #'company-complete-if-explicit)

with

;; <return> is for windowed Emacs; RET is for terminal Emacs
(dolist (key '("<return>" "RET"))
  ;; Here we are using an advanced feature of define-key that lets
  ;; us pass an "extended menu item" instead of an interactive
  ;; function. Doing this allows RET to regain its usual
  ;; functionality when the user has not explicitly interacted with
  ;; Company.
  (define-key company-active-map (kbd key)
    `(menu-item nil company-complete
                :filter ,(lambda (cmd)
                           (when (company-explicit-action-p)
                             cmd)))))

Now RET will act like normal when I don't interact with Company, but it will insert the selected completion when I have interacted with Company—in both terminal and windowed Emacs.

Here is the complete patch.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.