0

When ido-use-virtual-buffers is set to t, ido-switch-buffer shows, after the list of live buffers, a list of killed file buffers in chronological order, last killed first. Those are what Ido calls virtual buffers.

I'd like to have a command – I'll call it ido-find-virtual-buffer-file – that prompts for a virtual buffer, offering the virtual buffers from that list as completion candidates. In other words, ido-find-virtual-buffer-file would work just like ido-switch-buffer except that it would omit the list of live buffers.

This would make it a quick operation to reopen a recently killed file and in particular, if ido-find-virtual-buffer-file was bound to, say, C-c r, then C-c r RET would directly open the most recently killed file.

Arch Stanton
  • 1,657
  • 11
  • 23
  • Check the variable ido-virtual-buffers: IIUC, that's exactly what you need. – NickD Mar 12 '24 at 16:41
  • @NickD I wish it was. That's just a copy of recentf-list with fontification added, as far as I understand. Crucially, buffers are not in the same order as they appear in the completion candidates of ido-switch-buffer. However, Ido uses the function ido-add-virtual-buffers-to-list to attach the list of virtual buffers to the list of live buffers. I've tried to turn that into a function that makes a standalone list of virtual buffers and it seems to work. An edit is coming soon. Can you take a look at it, please? – Arch Stanton Mar 12 '24 at 17:11
  • The doc string says: "This is a copy of ‘recentf-list’, /pared down/ and with faces applied." (my emphasis). I certainly don't know the code at all, but it seems to me that doing a (setq ido-virtual-buffers nil) at the beginning of your function is questionable. I would need to understand the rest of the code that modifies ido-virtual-bufers much better to make any constructive comments. – NickD Mar 12 '24 at 21:48
  • it seems to me that doing a (setq ido-virtual-buffers nil) at the beginning of your function is questionable I thought the same but it's in ido-add-virtual-buffers-to-list, the function works, so I kept it. I think the function rebuilds ido-virtual-buffers where it does (push (cons name head) ido-virtual-buffers).

    – Arch Stanton Mar 12 '24 at 21:53
  • @NickD My code is working fine after a bit of testing, except for the issue I described in the last edit. I'm still trying to understand it. I'm wondering if it's related to scoping issues described in the manual. Anyway, I can't figure out how to make Ido ignore the candidates it should ignore. – Arch Stanton Mar 12 '24 at 21:56
  • I just don't see why it needs to be rebuilt - modified appropriately for the current operation, maybe; but why start from scratch? In any case, those are questions that I need to answer for myself: as I said, I don't know the code so if it works for you, that's all that's needed. – NickD Mar 12 '24 at 21:57
  • @NickD Could it be that it rebuilds ido-virtual-buffers to sort it according to the order in which the buffers have been killed? recentf-list is sorted according to the order in which the files have been visited. – Arch Stanton Mar 12 '24 at 23:44

1 Answers1

0

I've written this thing adapting my-ido-make-virtual-buffer-list from ido-add-virtual-buffers-to-list (cf.). I didn’t understand it 100% and even what I think I understood I might have gotten wrong. But it works. So far.

(defun my-ido-make-virtual-buffer-list ()
  "Return the list of virtual buffers – i.e. the history of killed file
buffers, last killed first – with the face ‘ido-virtual’ applied."
  ;; Make let-bindings of ‘ido-process-ignore-lists’ and ‘ido-ignored-list’
  ;; dynamic within this ‘defun’. They are used by ‘ido-ignore-item-p’.
  ;; See ‘(info "(elisp) Dynamic Binding")’.
  ;; They are bound dynamically only within ‘ido.el’, because they’re defined
  ;; using ‘defvar’ without a ‘value’ argument.
  ;; See ‘(info "(elisp) Defining Variables")’.
  (defvar ido-process-ignore-lists)
  (defvar ido-ignored-list)
  (setq ido-virtual-buffers nil)
  (let (name
        ido-temp-list
        (ido-process-ignore-lists t)
        (ido-ignored-list nil))
    (dolist (head recentf-list)
      (setq name (file-name-nondirectory head))
      ;; In case HEAD is a directory with trailing /.  See bug#14552.
      (when (equal name "")
    (setq name (file-name-nondirectory (directory-file-name head))))
      (when (equal name "")
    (setq name head))
      (and (not (equal name ""))
           (null (let (file-name-handler-alist) (get-file-buffer head)))
           (not (assoc name ido-virtual-buffers))
           (not (ido-ignore-item-p name ido-ignore-buffers))
           (file-exists-p head)
           (push (cons name head) ido-virtual-buffers)))
    (when ido-virtual-buffers
      (if ido-use-faces
      (dolist (comp ido-virtual-buffers)
        (put-text-property 0 (length (car comp))
                   'face 'ido-virtual
                   (car comp))))
      (setq ido-temp-list
        (nconc ido-temp-list
           (nreverse (mapcar #'car ido-virtual-buffers)))))))

(defun my-ido-find-virtual-buffer-file () "Prompt for a virtual buffer (i.e. a recently killed file buffer) and visit its file." (interactive) (let* ((virtual-buffer (ido-completing-read "Virtual buffer: " (my-ido-make-virtual-buffer-list) nil nil nil t)) (filename (cdr (assoc virtual-buffer ido-virtual-buffers)))) (find-file filename))) (keymap-global-set "C-c r" #'ido-find-virtual-buffer-file)

Arch Stanton
  • 1,657
  • 11
  • 23