help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Completion: display of candidates


From: Tassilo Horn
Subject: Re: Completion: display of candidates
Date: Tue, 19 Feb 2019 08:27:49 +0100
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

>> Right, and here comes the next problem: concretely I get my
>> completions from `locate --basename <pattern>`.  So the user (me)
>> might enter a wildcard pattern like "foo*bar.*".  But the
>> completions/matches obviously have no * in it, so no completion
>> matches the candidates.
>
> That completely depends on the completion style.
>
> For example `partial-completion` (which is included in the default
> `completion-styles`) does accept * so you can do `M-x r*v*uf TAB` to
> find revert-buffer.

Hm, that there can be dependencies between (1) finding completion
candidates and (2) completion styles doesn't spark joy in my heart.  I
thought of (1) as a kind of generic backend and (2) as a frontend which
users select based on personal preference.  But since both have to work
with the user's input string, I don't see how to make it better...

>> How to handle that?  Use the PREDICATE argument in completing-read so
>
> The PREDICATE argument can only rule out matches, not add new ones.

Yeah, in the end I've waived my hands and went without text properties
and just selected a unicode character which is unlikely to be used in
file names as separator.  The results are quite satisfying.

--8<---------------cut here---------------start------------->8---
(defconst th/recentf-locate-excluded-paths
  (let ((home (getenv "HOME")))
    (list
     #'backup-file-name-p
     (expand-file-name ".cargo/" home)
     (expand-file-name ".cache/" home)
     (expand-file-name ".m2/" home)
     (expand-file-name ".IntelliJIdea[^/]+/" home))))

(defun th/recentf-locate-completions (str)
  (with-current-buffer (get-buffer-create " *th/locate-matches*")
    (erase-buffer)
    (mapc (lambda (rf) (insert rf "\n")) recentf-list)
    (let ((home-dir (getenv "HOME"))
          lst line-move-visual)
      (when (> (length str) 2)
        (call-process "locate" nil t nil
                      "--basename"
                      "--existing"
                      "--ignore-case"
                      "--limit" "500"
                      str))
      (goto-char (point-min))
      (while (not (eobp))
        (let* ((path (buffer-substring (point) (line-end-position)))
               (basename (file-name-nondirectory path))
               (dir (file-name-directory path)))
          (unless (seq-find (lambda (pred)
                              (cond
                               ((stringp pred)
                                (string-match-p pred path))
                               ((functionp pred) (funcall pred path))
                               (t (error "Don't know how to handle %S" pred))))
                            th/recentf-locate-excluded-paths)
            (push (format "%s ‼ %s" basename dir) lst)))
        (next-line))
      (sort lst (lambda (a b)
                  (or
                   ;; a is in HOME but b is not, so sort a before b
                   (and (string-match-p (concat " ‼ " home-dir) a)
                        (not (string-match-p (concat " ‼ " home-dir) b)))
                   ;; otherwise sort by base name.
                   (string-lessp a b)))))))

(defun th/recentf-locate-file (locate-candidate)
  (interactive
   (list (completing-read
          "Locate File: "
          (completion-table-dynamic #'th/recentf-locate-completions)
          nil t)))
  (let ((path (progn
                (string-match "^\\(.*\\) ‼ \\(.*\\)$" locate-candidate)
                (expand-file-name (match-string 1 locate-candidate)
                                  (match-string 2 locate-candidate)))))
    (find-file path)))

(global-set-key (kbd "<f5>") #'th/recentf-locate-file)
--8<---------------cut here---------------end--------------->8---

Bye,
Tassilo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]