1

I'm trying to define a new sort function in icicles that sorts by flx score.

(defun icicle-flx-score-greater-p (s1 s2)
  (message "Testing testing!")
  (>
   (car (flx-score s1 icicle-current-input))
   (car (flx-score s2 icicle-current-input))))

(icicle-define-sort-command "by flx score"
                            ;; icicle-dirs-last-p
                            icicle-flx-score-greater-p
                            "Sort completions by flx score.")

However, trying to use this sort function results in:

Inappropriate sort order - reverting to UNSORTED

The funny thing, though, is that Testing testing! is never printed.

What am I doing wrong here?

  • FYI - I updated the answer, explaining your code error. – Drew Sep 19 '15 at 21:12
3

Here is a corrected version of your predicate definition:

(defun icicle-flx-score-greater-p (s1 s2)
  "Return non-nil if S1 scores higher than S2 using `flx-score`."
  ;; (message "Testing testing!")
  (let* ((input   (if (icicle-file-name-input-p)
                      (file-name-nondirectory icicle-current-input)
                    icicle-current-input))
         (score1  (flx-score s1 input))
         (score2  (flx-score s2 input)))
    (and score1  score2  (> (car score1) (car score2)))))

The problem you had was that flx-score can return nil instead of a cons, in which case an error is raised by predicate >. Icicles handles the error by turning off sorting. And because the error is handled, you do not see the output from the call to message (it appears, but you don't see it -- you can see this by using the debugger).

The other thing you need here (no error, but otherwise you won't get the comparison behavior you expect) is that for file-name completion you want to compare not the full input string, which typically is an absolute file name (it includes the directory), but just the nondirectory part of the input.

I've left my original answer, below, for more information. To find the problem (above) I downloaded flx.el and used the debugger. (It would probably have been enough to look at the code defining flx-score.)

(Next time, you might want to provide a link to the code that defines the function you use -- in this case, flx-score in flx.el.)

FYI -- I've now added a similar sort order to Icicles.


That error message means that the current sort order you've chosen is inappropriate for the kind of completion being performed by the current command. A few commands inhibit sorting altogether, but typically the error means that the sort function is inappropriate for the type of candidates being compared.

  1. The problem could also be as simple as having too many completion candidates to sort. Option icicle-sorting-max-candidates controls this.

  2. To simplify things, at least for testing, turn off icomplete-mode if you have it turned on. (You can use C-M-# during completion to toggle it.)

  3. If at any point the value of icicle-sort-comparer is nil, that's your problem -- that tells Icicles not to sort candidates.

  4. You need to load icicles-mac.el, to have macro icicle-define-sort-command available. But I assume you did that, or you would have mentioned a problem in that regard.

  5. As the doc string of that macro says, its argument COMPARISON-FUNCTION must compare two strings:

    COMPARISON-FN is a function that compares two strings, returning non-nil if and only if the first string sorts before the second.

Perhaps that is the problem here. Is the predicate you pass as COMPARISON-FUNCTION expecting string arguments?

What are sorted are completion candidates, which are strings. See the Icicles doc, page Sorting Candidates and Removing Duplicates, section Defining New Sort Orders.

That says this about COMPARISON-FUNCTION:

The second argument is the actual function used for sorting. It can be any function, including a lambda expression. The function takes two string arguments and returns non-nil if and only if the first string sorts before (is “less than”) the second.

For examples of using macro icicle-define-sort-command, see file icicles-mcmd.el. For examples of COMPARISON-FUNCTION, see file icicles-fn.el (look for section Icicles Functions - Sort Functions in that file).

In particular, in case it is appropriate for your context (dunno), icicles-fn.el contains examples of comparison functions, such as icicle-2nd-part-string-less-p, that compare two multi-completion candidates, that is, multi-part completion candidates.

If the problem is not so simple as the data that flx-score is returning, then you will need to look closer at what your sort predicate does.

The code that raises the error you see is in function icicle-reversible-sort. It essentially invokes the function that is the current value of variable icicle-sort-comparer (or if that value is a cons then it uses function icicle-multi-sort).

You can try M-x debug-on-entry icicle-reversible-sort, but that will plunge you in the debugger a lot -- be prepared to evaluate (cancel-debug-on-entry) easily, to cancel this. You can also try debugging your sort predicate, icicle-flx-score-greater-p. Probably the problem will be apparent from the first look you have of what it is doing with two completion-candidate string args. Again, you can try debug-on-entry to see what it is doing.

It's possible that the origin of the problem is the set of completion candidates, i.e., upstream of sorting. You can also start there, by using M-x debug-on-entry icicle-display-Completions. (Before using the debugger, be sure to load the source files (*.el, not *.elc).) If the candidates look OK to you, then move a bit downstream, to icicle-maybe-sort-maybe-truncate, which is the function that invokes icicle-reversible-sort.

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.