minad / corfu

:desert_island: corfu.el - COmpletion in Region FUnction
GNU General Public License v3.0
1.15k stars 43 forks source link

wrong-type-argument error with a custom capf #300

Closed kings2u closed 1 year ago

kings2u commented 1 year ago

I’m writing a capf that completes against names of Yasnippet snippets and expands into the selected snippet. This works by generating a list of string names of my yasnippets with my/generate-yas-capf-candidates that are completed against with my/cape-yasnippet-capf below.

The below code works just fine when I use (setq-local completion-at-point-functions '(my/cape-yasnippet-capf t):

(require 'yasnippet)

(defun my/generate-yas-capf-candidates ()
  "Generate list of candidates from each yasnippet for the current mode(s)."
  (let ((yasTemplates (yas--all-templates (yas--get-snippet-tables))))
    (mapcar
     (lambda (yasTemplate) 
       (yas--template-name yasTemplate))
     yasTemplates)))

(defvar my-yas-capf-candidates (my/generate-yas-capf-candidates))

(defun my/cape-yasnippet-capf ()
  "Function to be used for the hook `completion-at-point-functions'."
  (interactive)
  (let ((start (save-excursion (skip-syntax-backward "w_") 
                               (point)))
        (end (point)))
    (list start end
          my-yas-capf-candidates
          :exclusive 'no
          :annotation-function (lambda (_) " YAS")
          :exit-function (lambda (str status)
                           (delete-char (* -1 (length str))) 
                           (yas-expand-snippet (yas-lookup-snippet str)))))) 

However, it doesn’t work when I change the local completion-at-point-functions value as follows using cape-super-capf:

(setq-local completion-at-point-functions
            (list (cape-super-capf
                   #'my/generate-yas-capf-candidates
                   #'my-global-capf
                   #'cape-dabbrev)))

Here corfu--capf-wrapper generates an error: (wrong-type-argument number-or-marker-p "ALIAS defun"). ("ALIAS defun" is the name of the first yasnippet in the list generated by my/generate-yas-capf-candidates).

I would think this was an issue with cape-super-capf, which you have warned against using, except that the candidates I draw from my-global-capf below take the exact same form as those from my/generate-yas-capf-candidates; that is, they both generate a simple list of strings to complete against, and the following local combination generates no error:

(setq-local completion-at-point-functions
            (list (cape-super-capf
                   #'my-global-capf
                   #'cape-dabbrev)))

I know this is a flaw in my code, not your packages. Do you have any idea what I’m doing wrong?

minad commented 1 year ago

I don't see anything obviously wrong. My recommendation is to obtain a proper stack trace and to figure out where the error occurs exactly. If the error occurs in the post command hook it may not start the debugger, preventing you from obtaining the stack trace. Then you can try this code (see also https://github.com/minad/vertico#debugging-vertico):

(setq debug-on-error t)

(defun force-debug (func &rest args)
  (condition-case e
      (apply func args)
    ((debug error) (signal (car e) (cdr e)))))

(advice-add #'corfu--post-command :around #'force-debug)

Another question is if your Capf works without super-capf? Try to remove as much code as possible, such that you can narrow the issue down better. When does the error occur exactly?

I don't have further insight, since I neither use Yasnippet nor cape-super-capf. While cape-super-capf is problematic if you use complicated Capfs, I am not aware of any bugs. I recommend against using it since it may not give the expected result in all cases for all possible Capf combinations. But if the Capfs are all correctly written it should not result in errors.

Regarding Yasnippet - you may want to try my Tempel package. It is much simpler and just better. ;)

minad commented 1 year ago

Btw, what about https://github.com/elken/cape-yasnippet? Also did you try cape-company-to-capf with company-yasnippet? Any success with those? Someone should finally create a proper Yasnippet Capf since many people asked for this.

minad commented 1 year ago

@kings2u There seems to be a trivial mistake here:

(setq-local completion-at-point-functions
            (list (cape-super-capf
                   #'my/generate-yas-capf-candidates ;; NOT A CAPF!
                   #'my-global-capf
                   #'cape-dabbrev)))

I wonder how I missed that. Probably I didn't look close enough at the simpler parts of the code. :)

kings2u commented 1 year ago

There seems to be a trivial mistake here

Wow, that’s embarrassing. 😅 Thank you for spotting it! It works as expected now :)

what about https://github.com/elken/cape-yasnippet?

Yes, I was aware of this extension. At the moment it is limited to completing against candidates based on their Yasnippet shortcut key, rather than name of the snippet, but I believe the author intends to expand this.

did you try cape-company-to-capf with company-yasnippet?

I believe it had the same issue as cape-yasnippet for me explained above.

you may want to try my Tempel package. It is much simpler and just better. ;)

Absolutely! I intend to transition fully to it soon. I like the simplicity of design, and I’m not aware of any features of Yasnippet that aren’t in Tempel. Thanks again :)