Come riaprire il buffer appena ucciso, come CSt nel browser Firefox?


35

A volte uccido accidentalmente un buffer e voglio riaprirlo, proprio come CSt per annullare la scheda chiusa in Firefox, ma non esiste un comando integrato in Emacs, defun undo-kill-bufferin 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)))))

non funziona affatto. Se conosci elisp, come risolvere questo problema?

Se può mostrare un elenco dei buffer chiusi e loro posso sceglierne uno da riaprire, sarebbe meglio.


7
Nessuna delle risposte fornite finora risponde alla domanda posta, che riguarda la "riapertura" o il ripristino di un buffer ucciso. Questo perché è praticamente impossibile, in generale - il meglio che si potrebbe fare sarebbe ricrearlo. Ma se intendi solo buffer per la visita di file, la risposta è semplice e le risposte fornite qui sono appropriate. In tal caso , modifica la domanda per riflettere questa limitazione.
Disegnò il

2
Un approccio alternativo è quello di non uccidere quei buffer. bury-buffer è carino. Potresti anche immaginare un approccio più elaborato, ad esempio un kill-buffer (che non sarà ancora definito) che in seguito seppellirebbe immediatamente il buffer e creerebbe un timer per uccidere il buffer dopo pochi minuti. O un kill-buffer-forse-later che ucciderebbe il buffer se sta visitando un file, e ritarderebbe la sua morte se non lo è (forse anche anteporre uno spazio al suo nome per evitare il disordine quando si usa Cx b).
YoungFrog,

@YoungFrog, Esattamente, ho colto questa opportunità nella mia risposta.
Mark Karpov,

Risposte:


27

Ecco un'altra alternativa semplice che non richiede recentf. Collegando la prima funzione kill-buffer-hook, il nome file associato al buffer verrà inserito in un elenco. (Nota che, se uccidi un buffer che non sta visitando un file, è andato per sempre.) Quest'ultima funzione fa uscire quel file dall'elenco e lo visita:

(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))))

Si noti che killed-file-listè un elenco, quindi è possibile, ad esempio, scrivere una funzione più complessa per scorrere l'elenco, piuttosto che quella semplice qui descritta: dipende da te quanto si desidera farne.

EDIT: mi dispiace, ho perso l'ultima disposizione nella tua Q sulla richiesta di un elenco di file tra cui scegliere. La seguente funzione è leggermente più elaborata della versione precedente in quanto completing-readconsente di specificare quale dei file uccisi si desidera. Se stai usando qualcosa del genere ido, ti permetterà di scorrere tutti i file che hai ucciso nella sessione corrente, passando per impostazione predefinita al più recente. Si noti che presume che tu abbia già richiesto 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")))

5

Vorrei chiederti: "Vuoi davvero ucciderlo?". In effetti, uccidere un buffer è una cosa così comune nel mondo di Emacs, ma una volta ucciso, il buffer è sparito e, come dimostra la tua domanda, non è sempre desiderabile.

Tuttavia, possiamo scegliere un altro modo, in modo che non sia mai necessario ripristinare il buffer ucciso, preferendo solo seppellire l'uccisione. Dai un'occhiata al pacchetto Kill o Bury Alive , disponibile tramite MELPA .

Dalla descrizione del pacchetto:

Hai mai ucciso un buffer che potresti voler lasciare in vita? La motivazione per uccidere di solito è "per ora evitami", e uccidere potrebbe non essere la scelta migliore in molti casi a meno che la tua RAM non sia molto limitata. Questo pacchetto permette di insegnare a Emacs quali buffer vogliamo uccidere e quali preferiamo seppellire vivi.

Quando vogliamo davvero uccidere un buffer, si scopre che non tutti i buffer vorrebbero morire allo stesso modo. Il pacchetto consente di specificare come eliminare vari tipi di buffer. Ciò può essere particolarmente utile quando si lavora con alcuni buffer a cui è associato un processo, ad esempio.

Ma a volte potresti voler sbarazzarti della maggior parte dei buffer e portare Emacs in uno stato più o meno vergine. Probabilmente non vorrai uccidere il buffer di memoria virtuale e forse anche i buffer relativi all'ERC. È possibile specificare quali buffer eliminare.


4

Uso questa soluzione da questo post SO e funziona benissimo.

La soluzione è elegante ma non perfetta; memorizza un elenco di buffer attivi e restituisce il primo file dall'elenco recentf che non appartiene all'elenco dei buffer attivi.

;; Riapri l'ultimo buffer ucciso
;; Fonte: https://stackoverflow.com/questions/10394213/emacs-reopen-previous-killed-buffer
(richiede 'cl)
(richiede 'recentf)
(recentf-mode 1)
(defun undo-kill-buffer ()
  (Interattivo)
  (let ((active-files (loop per buf in (buffer-list)
                            when (buffer-file-name buf) lo raccoglie)))
    (loop per file nell'elenco recente
          salvo che (file active-files del file membro) ritorni (trova-file file))))

3

Devi accenderlo recentf-mode. Per farlo, corri M-x recentf-mode. Quindi, la funzione potrebbe non funzionare fino a quando non si aprono o si eliminano alcuni nuovi buffer; Non credo che avrai recentf-listcompilato.

Se vuoi che questo sia abilitato all'avvio di Emacs, inseriscilo nel tuo file init:

(recentf-mode)

Puoi quindi inserire il contenuto defuntrovato e associarlo a una chiave, se lo desideri.

Un aspetto negativo di questa modalità sembra essere che la modalità recentf è stata creata per tenere traccia dei openedfile, non di quelli uccisi. Quindi, se si esegue la funzione due volte, non riaprirà il secondo file ucciso più di recente.


4
Sebbene Emacs 24 abbia effettivamente reso questo opzionale per le modalità secondarie, sarei comunque propenso a scrivere (recentf-mode 1)con l'argomento esplicito, in modo che qualcuno riesaminando il proprio file init in Emacs 23 non finisca per disattivare nuovamente la modalità.
phils,

1

ErgoEmacs ha una funzione close-current-bufferche, in particolare, mantiene un elenco di buffer chiusi di recente:

(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)
     )
   )
 )

Quindi, usando questi si può riaprire questa sessione con il buffer chiuso

;; 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)))

1

EDIT: Non ho prestato attenzione quando ho risposto e ho risposto a qualcos'altro che l'OP non ha chiesto. Ancora una volta, mi dispiace. Grazie per le tue parole, @CodyChan.

Beh, non sono un veterano di Emacs, e forse questo forse è diventato disponibile solo nelle versioni recenti. So che verrò alcuni anni dopo, ma forse può essere utile per gli altri, poiché la mia ricerca mi ha portato qui.

Sono su Emacs v25.2.1, recentfè già disponibile qui e ha una funzione pronta che fa quello che ti serve. L'ho già attivato in passato su versioni precedenti, quindi .emacsho:

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

E questo ha funzionato perfettamente per me. Naturalmente, cambia la scorciatoia per quello che ti piace di più.


2
Sembra che la funzione esistesse già molto tempo fa, ovvero il 2005 secondo il file ChangeLog nell'albero del codice sorgente di Emacs. Funziona e può anche funzionare per riaprire il buffer chiuso dalla precedente sessione di Emacs, ma sembra che non possa elencare i buffer chiusi per farmi scegliere uno dall'elenco.
CodyChan,

2
Quindi non riapre specificamente il buffer ucciso, ma riapre i file aperti di recente.
CodyChan,

@CodyChan, mi dispiace molto e ovviamente hai ragione. Sarebbe il file aperto più di recente e non quello che hai chiesto. Presto cancellerò la risposta, mi scuso con te e gli altri compagni.
Charles Roberto Canato,

3
Per eliminare inutilmente questa risposta, forse qualcuno vuole solo che la tua soluzione riapri semplicemente i file aperti di recente. :)
CodyChan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.