minad / cape

🦸cape.el - Completion At Point Extensions
GNU General Public License v3.0
584 stars 20 forks source link

cape-company-to-capf's returned CAPF may not give sorted candidates through corfu #44

Closed daanturo closed 2 years ago

daanturo commented 2 years ago

Specifically I use elpy-company-backend via cape-company-to-capf.

image

cape-company-to-capf disables sorting when the backend reports itself as sorted (alphabetically in this case?):

       :sort (not (cape--company-call backend 'sorted))

Disabling the above :sort key make candidates appear sorted by length normally like other CAPFs through Corfu.

Can you expose a flag at CAPF creation time that can force sorting?

minad commented 2 years ago

You can use the cape-capf-properties transformer.

daanturo commented 2 years ago

use the cape-capf-properties transformer

Can you give an example how to use that function correctly? There hasn't been one in the README yet. I tried

(defalias #'my-elpy-company-capf
  (cape-capf-properties (cape-company-to-capf 'elpy-company-backend)
                        :sort t))

Still not sorted. I logged cape--table-with-properties and saw sort at nil.

minad commented 2 years ago

Hmm, this should work in principle. Did you check the backend sort function in Corfu? See corfu--sort-function. You can also check corfu--metadata.

daanturo commented 2 years ago

image

corfu--sort-function always return corfu-sort-length-alpha.

As I observed, the condition to return TABLE as-is is most of the time as truthy/falsy as SORT. So it either returns TABLE without sorting (SORT as t) or modified TABLE with SORT as nil.

daanturo commented 2 years ago

Looks like at cape-wrap-properties:

;;;###autoload
(defun cape-wrap-properties (capf &rest properties)
  "Call CAPF and add additional completion PROPERTIES.
Completion properties include for example :exclusive, :annotation-function and
the various :company-* extensions. Furthermore a boolean :sort flag and a
completion :category symbol can be specified."
  (pcase (funcall capf)
    (`(,beg ,end ,table . ,plist)
     (my-message "708 cape.el"
                 ;; This expr is always `t'
                 (or (not table)
                     (and (not (plist-get plist :category))
                           properties)))
     `(,beg ,end
            ,(apply #'cape--table-with-properties table properties)
            ,@properties ,@plist))))

The arguments passed to cape--table-with-properties will always satisfy the if condition so TABLE is returned unmodified (non-nil TABLE, no category, :SORT t).

Edit: sorting with cape-capf-properties is now achieved if at cape--table-with-properties's first if condition, I reduce

(or (not table) (and (not category) sort))

to

(not table)
minad commented 2 years ago

corfu--sort-function always return corfu-sort-length-alpha.

Well, that's good then. This means that the sort function of the backend is ignored as you wanted? You can also chose a different sort function, e.g. the one from corfu-history.

daanturo commented 2 years ago

Well, that's good then. This means that the sort function of the backend is ignored as you wanted?

No, I meant sorting by length wasn't applied at that time despite the correct returned value of corfu--sort-function. I think the problem lies at cape--table-with-properties's (and (not category) sort) as commented above, cape-capf-properties indeed works after removing that condition.

(cl-defun cape--table-with-properties (table &key category (sort t) &allow-other-keys)
  (if (or (not table) ;; (and (not category) sort)
          )
      table
    (let ((metadata `(metadata
                      ,@(and category `((category . ,category)))
                      ,@(and (not sort) '((display-sort-function . identity)
                                          (cycle-sort-function . identity))))))
      (lambda (str pred action)
        (if (eq action 'metadata)
            metadata
          (complete-with-action action table str pred))))))
minad commented 2 years ago

Btw, you can also use corfu-sort-override-function in case you disagree with the sort function specified by the backend.

daanturo commented 2 years ago

!! Without modifying cape's source or touching corfu-sort-override-function, this can be worked around by enforcing :category using cape-capf-properties so that (and (not category) sort) is always nil.

Edit: thank you!