prescient.el icon indicating copy to clipboard operation
prescient.el copied to clipboard

How to disable prescient in counsel-find-file?

Open arthurcgusmao opened this issue 5 years ago • 9 comments

Hi, for some reason adding find-file or counsel-find-file to a negated list in ivy-prescient-sort-commands has no effect, and the function continues to have its candidates sorted. I can tell it is prescient that is doing this because disabling ivy-prescient-mode automatically disables sorting of find-file. Any ideas on how I can get this to work? I have configured the variable in the following manner:

(use-package prescient
  :config
  (setq prescient-save-file (concat acg/history-dir "prescient-save.el"))
  (prescient-persist-mode 1))

(use-package ivy-prescient
  :after (prescient ivy)
  :config
  (setq ivy-prescient-sort-commands '(:not swiper swiper-isearch ivy-switch-buffer counsel-find-file counsel-recentf))
  (ivy-prescient-mode 1))

(use-package company-prescient
  :after (prescient company)
  :config (company-prescient-mode 1))

arthurcgusmao avatar Jun 27 '20 16:06 arthurcgusmao

You could check to make sure the command you expect is being run, with C-h k C-x C-f. Aside from that, however, your configuration looks exactly correct and I would suspect a bug in Ivy.

raxod502 avatar Jun 28 '20 12:06 raxod502

Thank you @raxod502. The function being run is indeed find-file (or counsel-find-file); both calls result in the same Ivy interface, and adding any or both to ivy-prescient-sort-commands has no effect. I also tried adding the many subfunctions that Counsel leverages to find file (like counsel--find-file-1) with no success.

It must be something with the way counsel-find-file works, but I couldn't figure out exactly what. What is strange is that negating counsel-recentf in ivy-prescient-sort-commands works, but not counsel-find-file.

arthurcgusmao avatar Jun 28 '20 14:06 arthurcgusmao

Yeah, I'm afraid I'm not sure what's happening there. It does sure seem like counsel-find-file is getting passed as the CALLER argument to ivy-read. You have probably found a bug in something. See also #65.

raxod502 avatar Jun 30 '20 13:06 raxod502

Yep. This is almost certainly an edge case. Here

https://github.com/abo-abo/swiper/blob/d2891aab7b816aebf21ebd01ce33933a6ac6244f/ivy.el#L2271-L2317

there's an explicit call to ivy--sorted-files (probably because ivy sorts directories first by default) and it uses (ivy--sort-function #'read-file-name-internal) which evaluates to ivy-prescient--enable-sort-commands. I don't think there's a way to fix this on the ivy side (and I kinda understand why selectrum is a thing now), but we can probs setup a workaround in prescient.

mohkale avatar Dec 29 '20 07:12 mohkale

I've managed to get file-name completion back to normal using this:

(add-hook 'ivy-prescient-mode-hook
          (defun ivy-prescient-disable-sort-find-file+ ()
            (when (and (eq (car ivy-prescient-sort-commands) :not)
                       (memq 'counsel-find-file
                             (cdr ivy-prescient-sort-commands)))
              (ivy--alist-set 'ivy-sort-functions-alist
                              #'read-file-name-internal #'ivy-sort-file-function-default))))

but it doesn't disable sorting based on ivy-prescient-sort-commands so it's not really a fix for this issue. It's good enough for my use cases so I'm leaving it here :-).

mohkale avatar Dec 29 '20 17:12 mohkale

Is there something similar to disable it for selectrum-prescient.el for certain commands?

unhammer avatar Jan 08 '21 12:01 unhammer

@unhammer

There's selectrum-should-sort-p which you can set to nil to disable sorting. However for functions like find-file the sorting already appears to be garbled which makes it kind of useless. If you want ivy like sorting with find-file you can try this:

(defvar selectrum-find-file-keep-prescient-sorting+ nil
  "When true, `selectrum-find-file' keeps sorting based on `prescient-sort' but
still tries to group directories before files..")

(defun selectrum-prescient-preprocess+ (func cands)
  (cond
   ;; Finding file-names should sort directories first.
   ((eq minibuffer-completion-table 'read-file-name-internal)
    (if selectrum-find-file-keep-prescient-sorting+
        ;; WARN: Adapted from ivy, doesn't maintain prescient based sorting
        (cl-loop for cand in (funcall func cands)
                 with dirs  = nil
                 with files = nil
                 do (if (eq (aref cand (- (length cand) 1)) ?/)
                        (setq dirs (cons cand dirs))
                      (setq files (cons cand files)))
                 finally return `(,@(nreverse dirs) ,@(nreverse files)))
      (sort cands
            (lambda (x y)
              (let ((x-dir (eq (aref x (- (length x) 1)) ?/))
                    (y-dir (eq (aref y (- (length y) 1)) ?/)))
                (cond
                 ((and x-dir y-dir)
                  (string< (directory-file-name x) (directory-file-name y)))
                 (x-dir t)
                 (y-dir nil)
                 (t (string< x y))))))))
   (t (funcall func cands))))

(advice-add 'selectrum-prescient--preprocess :around #'selectrum-prescient-preprocess+)

mohkale avatar Jan 13 '21 18:01 mohkale

Just found selectrum-should-sort-p, seems to work for my uses :-)

unhammer avatar Jan 13 '21 20:01 unhammer

Is there something similar to disable it for selectrum-prescient.el for certain commands?

See also discussion on the Selectrum side about adding a way to configure completion behavior on a per-command basis: https://github.com/raxod502/selectrum/issues/265

Fair warning, it is nontrivial, assuming that we actually want to do it in a reliable and not-surprising-to-the-user way, rather than as a hack.

raxod502 avatar Jan 17 '21 17:01 raxod502