oantolin / orderless

Emacs completion style that matches multiple regexps in any order
GNU General Public License v3.0
776 stars 27 forks source link

[FR] Add option for find-file to match only file name. #160

Closed gety9 closed 9 months ago

gety9 commented 9 months ago

Imho from user experience point of view in 95% of the cases if person searching for file he wants only to match file name (it's file search, not directory search)

I my opinion it should be default, if not at least to have option to set it to true with setq / customize.

Here is person trying to achieve same thing https://www.reddit.com/r/emacs/comments/1758q2c/consultvertigoorderless_how_to_not_include/ (seems like it's possible with custom dispatacher... but shouldn't it be easier to set (if not default?))

minad commented 9 months ago

This is not an Orderless issue. In the issue on reddit, the candidates are generated by consult-ls-git, which is responsible for the filtering and sorting.

oantolin commented 9 months ago

This is out of scope for orderless since orderless only deals with strings and has no idea what a file path is!

Fortunately, Orderless is highly configurable, so users can handle this sort of thing in their own configuration. For example:

(defun match-only-file-name (pattern _index _total) 
  (when (string-prefix-p "/" pattern)
    (cons 'orderless-regexp
          (rx (group (literal (substring pattern 1)))
              (zero-or-more (not ?/)) string-end))))

(push #'match-only-file-name orderless-style-dispatchers)

This makes /ll match ll but only if there are no slashes after it, i.e., in the file portion of a file path. You can make different choices: for example you could decide not to require any special prefix and to always use the style when you are matching files (which requires knowing what completion category is indicated by the commands you want to use it for):

(defun match-only-file-name (pattern _index _total)
  (when (memq (completion-metadata-get
               (completion-metadata
                (buffer-substring-no-properties
                 (minibuffer-prompt-end)
                 (max (minibuffer-prompt-end) (point)))
                minibuffer-completion-table
                minibuffer-completion-predicate)
               'category)
              '(file project-file)) ; add whatever categories you need
    (cons 'orderless-regexp
          (rx (group (literal pattern))
              (zero-or-more (not ?/)) string-end))))

Please let me know if you need help tweaking those style dispatchers for your exact use case.

oantolin commented 9 months ago

(By the way, rx is growing on me. I haven't memorized the syntax and still lookup its docstring every time I use it, but while I find writing regexps easier, I vastly prefer reading rx calls.)

minad commented 9 months ago

@oantolin The matcher you wrote will work nicely for filtering in recentf-open (or post filtering in consult-fd or consult-ls-git), but iiuc this is not what the issue is about, see https://www.reddit.com/r/emacs/comments/1758q2c/consultvertigoorderless_how_to_not_include/. I think the goal is to change the way fd or git find and order the files.

oantolin commented 9 months ago

Maybe, @minad, I'm not sure. I had interpreted this issue and that reddit post as asking two slightly different things: this issue asks to match only in the file name part and that reddit post talks about scoring, giving file name matches priority.

gety9 commented 9 months ago

@oantolin thank you for the code, you interpreted me right

@minad you are right, reddit post was on "consult-ls-git" :) i didn't even notice. I was talking about regular recentf (in find-file or consult-buffer)

gety9 commented 9 months ago

@oantolin

I just now get back home (had small vocation), and tested the code you've suggested. Not working for me: edit_20240214112101 query for "cfg" should've brought only binv__cfg.toml (but it also brings files in /Books/AppCfg/ dir (all of them are in this folder, it's just that i truncate long names))

Same for other queries.. ex "binv" should've brought only files having binv in name (but it also brings other files in "Binv" dir)...

Could pleaese tell what am i doing wrong?

Config:

(use-package consult
  :config
  (consult-customize
    consult-buffer :preview-key ">"
    consult-line   :preview-key ">"))

(use-package embark
  :demand t)
(use-package embark-consult)

(defun my/vertico-truncate-candidates (args)
  (if-let ((arg (car args))
           (type (get-text-property 0 'multi-category arg))
           ((eq (car-safe type) 'file))
           (w (max 25 (- (window-width) 55)))
           (l (length arg))
           ((> l w)))
      (setcar args (concat "…" (truncate-string-to-width arg l (- l w)))))
  args)
(advice-add #'vertico--format-candidate :filter-args #'my/vertico-truncate-candidates)
(use-package vertico
  :init
  (vertico-mode))

(use-package marginalia
  :init
  (marginalia-mode))

(defun my/match-only-file-name (pattern _index _total)
  (when (memq (completion-metadata-get
               (completion-metadata
                (buffer-substring-no-properties
                 (minibuffer-prompt-end)
                 (max (minibuffer-prompt-end) (point)))
                minibuffer-completion-table
                minibuffer-completion-predicate)
               'category)
              '(file project-file))
    (cons 'orderless-regexp
          (rx (group (literal pattern))
              (zero-or-more (not ?/)) string-end))))
(use-package orderless
  :demand t
  :init
  (setq completion-styles '(orderless)
    orderless-smart-case nil
    read-file-name-completion-ignore-case t
    read-buffer-completion-ignore-case t
    completion-ignore-case t)
  :config
  (push #'my/match-only-file-name orderless-style-dispatchers))