Comment rouvrir un tampon tué, comme CSt dans le navigateur Firefox?

35

Parfois, je tue accidentellement un tampon et souhaite le rouvrir, tout comme CSt pour annuler l'onglet fermé dans Firefox, mais il n'y a pas de commande intégrée dans Emacs, defun undo-kill-bufferdans http://www.emacswiki.org/RecentFiles :

(defun undo-kill-buffer (arg)
  "Re-open the last buffer killed.  With ARG, re-open the nth buffer."
  (interactive "p")
  (let ((recently-killed-list (copy-sequence recentf-list))
     (buffer-files-list
      (delq nil (mapcar (lambda (buf)
                  (when (buffer-file-name buf)
                (expand-file-name (buffer-file-name buf)))) (buffer-list)))))
    (mapc
     (lambda (buf-file)
       (setq recently-killed-list
         (delq buf-file recently-killed-list)))
     buffer-files-list)
    (find-file
     (if arg (nth arg recently-killed-list)
       (car recently-killed-list)))))

ne fonctionne pas du tout. Si vous connaissez elisp, comment résoudre ce problème?

S'il peut afficher une liste des mémoires tampons fermées et que je peux en choisir un pour les rouvrir, ce serait mieux.

CodyChan
la source
7
Aucune des réponses données jusqu’à présent ne répond à la question telle qu’elle est posée, à savoir «rouvrir» ou restaurer un tampon tué. C'est parce que c'est à peu près impossible, en général - le mieux qu'on puisse faire serait de le recréer. Mais si vous voulez parler uniquement des mémoires tampons de visite de fichier, la réponse est facile et les réponses fournies ici sont appropriées. Si tel est le cas, veuillez modifier votre question pour refléter cette restriction.
Drew
2
Une autre approche consiste à ne pas tuer ces tampons. Bury-Buffer est sympa. Vous pouvez également imaginer une approche plus sophistiquée, par exemple un kill-buffer-plus tard (encore à définir) qui enterre immédiatement le buffer et configure un timer pour tuer le buffer au bout de quelques minutes. Ou un kill-buffer-peut-être plus tard qui tuerait le tampon s'il visitait un fichier et retarderait sa mort s'il ne le faisait pas (peut-être aussi ajouter un espace à son nom pour éviter l'encombrement lorsque Cx b est utilisé).
YoungFrog
@YoungFrog, Exactement, j'ai parlé de cette opportunité dans ma réponse.
Mark Karpov

Réponses:

27

Voici une autre alternative simple qui ne nécessite pas recentf. Accrocher la première fonction en kill-buffer-hookpoussera le nom de fichier associé au tampon dans une liste. (Notez que si vous supprimez un tampon qui ne visite pas un fichier, il disparaît définitivement.) Cette dernière fonction supprime ce fichier de la liste et le visite:

(defvar killed-file-list nil
  "List of recently killed files.")

(defun add-file-to-killed-file-list ()
  "If buffer is associated with a file name, add that file to the
`killed-file-list' when killing the buffer."
  (when buffer-file-name
    (push buffer-file-name killed-file-list)))

(add-hook 'kill-buffer-hook #'add-file-to-killed-file-list)

(defun reopen-killed-file ()
  "Reopen the most recently killed file, if one exists."
  (interactive)
  (when killed-file-list
    (find-file (pop killed-file-list))))

Notez qu’il killed-file-lists’agit d’une liste. Vous pouvez, par exemple, écrire une fonction plus complexe pour parcourir cette liste, plutôt que la simple décrite ici: c’est à vous de décider combien vous voulez en faire.

EDIT: désolé, j'ai raté la dernière disposition de votre Q sur le fait de vouloir une liste de fichiers parmi lesquels choisir. La fonction suivante est légèrement plus sophistiquée que la version ci-dessus dans la mesure où elle completing-readvous permet de spécifier le fichier que vous souhaitez supprimer. Si vous utilisez quelque chose du genre ido, cela vous permettra de parcourir tous les fichiers que vous avez supprimés au cours de la session en cours, les plus récents par défaut. Notez que cela suppose que vous avez déjà requis cl-lib:

(defun reopen-killed-file-fancy ()
  "Pick a file to revisit from a list of files killed during this
Emacs session."
  (interactive)
  (if killed-file-list
      (let ((file (completing-read "Reopen killed file: " killed-file-list
                                   nil nil nil nil (car killed-file-list))))
        (when file
          (setq killed-file-list (cl-delete file killed-file-list :test #'equal))
          (find-file file)))
    (error "No recently-killed files to reopen")))
Dan
la source
5

Je voudrais vous demander: "Voulez-vous vraiment le tuer?". En effet, tuer un tampon est une chose tellement courante dans le monde Emacs, mais une fois tué, le tampon est parti, et comme votre question le démontre, ce n'est pas toujours souhaitable.

Cependant, nous pouvons choisir une autre méthode, pour que vous n'ayez jamais besoin de restaurer la mémoire tampon tuée - préférez simplement enterrer à tuer. Jetez un coup d'œil au paquet Kill ou Bury Alive , il est disponible via MELPA .

De la description du paquet:

Avez-vous déjà tué un tampon que vous voudriez laisser en vie? La motivation pour tuer signifie généralement «s'écarter de mon chemin pour le moment», et tuer ne constitue peut-être pas le meilleur choix dans de nombreux cas, à moins que votre RAM ne soit très très limitée. Ce paquet permet d'apprendre à Emacs quels tampons nous voulons tuer et ceux que nous préférons enterrer vivants.

Lorsque nous voulons vraiment tuer un tampon, il s'avère que tous les tampons ne veulent pas mourir de la même façon. Le package permet de spécifier comment tuer différents types de tampons. Cela peut être particulièrement utile lorsque vous travaillez avec un tampon associé à un processus, par exemple.

Mais parfois, vous voudrez peut-être vous débarrasser de la plupart des tampons et amener Emacs dans un état plus ou moins vierge. Vous ne voulez probablement pas supprimer le tampon de travail et peut-être aussi les tampons liés à ERC. Vous pouvez spécifier les tampons à purger.

Mark Karpov
la source
4

J'utilise cette solution depuis ce poste SO et cela fonctionne bien.

La solution est élégante mais pas parfaite. il stocke une liste des tampons actifs et renvoie le premier fichier de la liste recentf qui n'appartient pas à la liste des tampons actifs.

;; Rouvrir le dernier tampon tué
;; Source: https://stackoverflow.com/questions/10394213/emacs-reopen-previous-killed-buffer
(nécessite 'cl)
(nécessite 'recentf)
(recentf-mode 1)
(defun undo-kill-buffer ()
  (interactif)
  (let ((active-files (boucle pour buf in (liste de tampons)))
                            quand (tampon-nom-fichier buf) le récupère)))
    (boucle pour le fichier dans recentf-list
          à moins que (fichiers actifs du fichier membre) retourne (fichier-recherche))))
Kaushal Modi
la source
3

Vous devez allumer recentf-mode. Pour ce faire, lancez M-x recentf-mode. Ensuite, la fonction risque de ne pas fonctionner tant que vous n'avez pas ouvert ou supprimé de nouveaux tampons. Je ne pense pas que vous aurez recentf-listrempli.

Si vous voulez que ceci soit activé quand Emacs démarre, mettez ceci dans votre fichier init:

(recentf-mode)

Vous pouvez ensuite mettre le que defunvous avez trouvé dedans et le lier à une clé, si vous le souhaitez.

Un inconvénient de ce mode semble être que le mode recentf est conçu pour suivre les openedfichiers, pas ceux qui ont été tués. Ainsi, si vous exécutez la fonction deux fois, elle ne rouvrira pas votre deuxième fichier récemment tué.

zck
la source
4
Bien qu'Emacs 24 ait effectivement rendu cette option facultative pour les modes mineurs, je serais quand même enclin à écrire (recentf-mode 1)avec l'argument explicite, de sorte que quelqu'un réévaluant son fichier init sous Emacs 23 ne finisse pas par désactiver le mode.
phils
1

ErgoEmacs a une fonction close-current-bufferqui garde notamment une liste des tampons récemment fermés:

(defvar recently-closed-buffers (cons nil nil) "A list of recently closed buffers. The max number to track is controlled by the variable recently-closed-buffers-max.")
(defvar recently-closed-buffers-max 10 "The maximum length for recently-closed-buffers.")

(defun close-current-buffer ()
"Close the current buffer.

Similar to (kill-buffer (current-buffer)) with the following addition:

• prompt user to save if the buffer has been modified even if the buffer is not associated with a file.
• make sure the buffer shown after closing is a user buffer.
• if the buffer is a file, add the path to the list recently-closed-buffers.

A emacs buffer is one who's name starts with *.
Else it is a user buffer."
 (interactive)
 (let (emacsBuff-p isEmacsBufferAfter)
   (if (string-match "^*" (buffer-name))
       (setq emacsBuff-p t)
     (setq emacsBuff-p nil))

   ;; offer to save buffers that are non-empty and modified, even for non-file visiting buffer. (because kill-buffer does not offer to save buffers that are not associated with files)
   (when (and (buffer-modified-p)
              (not emacsBuff-p)
              (not (string-equal major-mode "dired-mode"))
              (if (equal (buffer-file-name) nil) 
                  (if (string-equal "" (save-restriction (widen) (buffer-string))) nil t)
                t
                )
              )
     ;; (progn ;; I'VE ADDED THIS LINE
     ;;   (switch-to-buffer (buffer-name)) ;; AND THIS LINE
     (if (y-or-n-p
          (concat "Buffer " (buffer-name) " modified; Do you want to save?"))
         (save-buffer)
       (set-buffer-modified-p nil))
     ;; ) ;; AND ALSO A PARENTHESIS HERE
     )

   ;; save to a list of closed buffer
   (when (not (equal buffer-file-name nil))
     (setq recently-closed-buffers
           (cons (cons (buffer-name) (buffer-file-name)) recently-closed-buffers))
     (when (> (length recently-closed-buffers) recently-closed-buffers-max)
           (setq recently-closed-buffers (butlast recently-closed-buffers 1))
           )
     )

   ;; close
   (kill-buffer (current-buffer))

   ;; if emacs buffer, switch to a user buffer
   (if (string-match "^*" (buffer-name))
       (setq isEmacsBufferAfter t)
     (setq isEmacsBufferAfter nil))
   (when isEmacsBufferAfter
     (next-user-buffer)
     )
   )
 )

Donc, en utilisant ceux-ci, on peut rouvrir ce tampon fermé de session avec

;; undo close this-session buffer:
(defun ergo-undo-close-buffer ()
  "Opens some this-session closed buffer."
  (interactive)
  (let* ((mylist (delq nil (delete-dups (mapcar 'car recently-closed-buffers))))
         (baseName (ido-completing-read "Open this session closed buffer: " mylist))
         (fileName (cdr (assoc baseName recently-closed-buffers))))
    (find-file fileName)))
Adobe
la source
1

EDIT: Je n'ai pas fait attention en répondant, et j'ai répondu à quelque chose d'autre que le PO n'a pas demandé. Encore une fois, je suis désolé. Merci pour vos mots, @CodyChan.

Eh bien, je ne suis pas un vétéran d’Emacs, et peut-être que cela n’est peut-être devenu disponible que dans les versions récentes. Je sais que j'arrive quelques années plus tard, mais peut-être que cela peut être utile pour les autres, car ma recherche m'a amené ici.

Je suis sur Emacs v25.2.1, recentfest déjà disponible ici et a une fonction prête qui fait ce dont vous avez besoin. Je l'avais déjà activé par le passé sur les anciennes versions, alors j'ai .emacs:

(recentf-mode 1)
(global-set-key (kbd "C-S-t") 'recentf-open-most-recent-file)

Et cela a parfaitement fonctionné pour moi. Bien sûr, changez le raccourci pour ce qui vous plait le plus.

Charles Roberto Canato
la source
2
Il semble que la fonction existait déjà il y a longtemps, c'est-à-dire 2005 d'après le fichier ChangeLog dans l'arborescence du code source d'Emacs. Cela fonctionne, et cela peut même fonctionner pour rouvrir le tampon fermé de la session précédente d'Emacs, mais il semble qu'il ne puisse pas lister les tampons fermés pour me permettre d'en choisir un dans la liste.
CodyChan
2
Donc, il ne rouvre pas simplement le tampon tué spécifiquement, mais rouvre les fichiers récemment ouverts.
CodyChan
@CodyChan, je suis vraiment désolé et bien sûr tu as raison. Ce serait le fichier récemment ouvert et non ce que vous avez demandé. Je vais supprimer la réponse bientôt, je m'excuse auprès de vous, ainsi que d'autres copains.
Charles Roberto Canato
3
Inutile de supprimer cette réponse, il se peut que quelqu'un souhaite simplement que votre solution rouvre simplement les fichiers récemment ouverts. :)
CodyChan