copilot-emacs / copilot.el

An unofficial Copilot plugin for Emacs.
MIT License
1.79k stars 126 forks source link

Allow for better integration with lsp-mode / company-mode. #108

Closed wusticality closed 1 year ago

wusticality commented 1 year ago

At present (and per the documentation), if something like company-mode is enabled, copilot candidates will still be rendered underneath company-mode. I'm using company-box to improve this a bit, but I'd prefer to have the behavior of other editors (JetBrains, et al) that will only show copilot recommendations if the language server isn't currently showing you something. For example, in something like CLion, if you type a . after an identifier, it will popup intellisense, and only if you C-g that popup will copilot recommendations be displayed.

I have tried to get around this doing something like this:

(defun my-copilot-disable-predicate ()
  "When copilot should not automatically show completions."
  (if (company--active-p) t nil))

(use-package copilot
  :straight (:host github :repo "zerolfx/copilot.el" :files ("dist" "*.el"))
  :after company
  :config
  (progn
    ;; Enable copilot for programming modes.
    (add-hook 'prog-mode-hook 'copilot-mode)

    ;; When to show / hide predicates.
    (add-to-list 'copilot-disable-predicates #'my-copilot-disable-predicate)

    ;; Complete using the tab key.
    (define-key copilot-completion-map (kbd "TAB") 'copilot-accept-completion)))

This doesn't seem to work quite right. Perhaps copilot only updates the overlay state if a key is pressed? I'm trying to figure this out by looking at the source (I know that the disabling predicates are inspected in copilot--post-command-debounce which is called from copilot--post-command but I can't quite figure out when the overlay state is fully reset).

Finally, I should mention that I'm using this in conjunction with lsp-mode (which is using company-mode for candidates). In a perfect world, I would be able to have the following behavior:

Thanks very much for your help and for this great package!

zerolfx commented 1 year ago

Fixed in #110.

You can use (add-to-list 'copilot-disable-display-predicates #'company--active-p).

wusticality commented 1 year ago

Hey, thanks again for your hard work! :)

I've updated to grab your latest changes and though it's improved, the candidate is still shown once you type a . after an identifier:

image

Once I type the next character it disappears:

image

Would it be possible to fix this? Perhaps copilot could constantly check in a loop instead of in response to events?

Another issue is that if you type a . after an identifier, then cancel company-box with C-g, it won't show completions until you type another character.

For clarity, my config now looks like this:

(use-package copilot
  :straight (:host github :repo "zerolfx/copilot.el" :files ("dist" "*.el"))
  :after company
  :config
  (progn
    ;; Enable copilot for programming modes.
    (add-hook 'prog-mode-hook 'copilot-mode)

    ;; When to show / hide predicates.
    (add-to-list 'copilot-disable-predicates #'company--active-p)    
    (add-to-list 'copilot-disable-display-predicates #'company--active-p)

    ;; Complete using the tab key.
    (define-key copilot-completion-map (kbd "TAB") 'copilot-accept-completion)))
zerolfx commented 1 year ago

@wusticality The problems you mentioned do exist but may be out of copilot.el's scope.

the candidate is still shown once you type a . after an identifier

It happens if Copilot's response arrives earlier than LSP's. In this case, when copilot.el tries to display completion, company--active-p returns nil. To solve the problem, you may add a hook so that when company shows completions, it calls copilot-clear-overlay.

Another issue is that if you type a . after an identifier, then cancel company-box with C-g, it won't show completions until you type another character.

To solve the problem, you may also need to add a hook. After canceling company-box, call copilot-complete.

Above are my suggestions, and I can't help you on copilot.el's side because they are more company-mode-related. But the good thing is that you are using Emacs, you can achieve these things by writing a few lines of elisp.

github-actions[bot] commented 1 year ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.

github-actions[bot] commented 1 year ago

This issue was closed because it has been stalled for 5 days with no activity.