Bagaimana cara membuka kembali buffer yang baru saja dimatikan, seperti CSt di Browser Firefox?

35

Terkadang saya secara tidak sengaja membunuh buffer dan ingin membukanya kembali, seperti halnya CSt untuk membatalkan tab yang tertutup di Firefox, tetapi tidak ada perintah bawaan di Emacs, defun undo-kill-bufferdi 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)))))

tidak bekerja sama sekali. Jika Anda tahu sedikit, bagaimana mengatasi masalah ini?

Jika itu dapat menunjukkan daftar buffer tertutup dan mereka saya dapat memilih satu dari mereka untuk membuka kembali, itu akan lebih baik.

CodyChan
sumber
7
Tidak ada jawaban yang diberikan sejauh menjawab pertanyaan yang diajukan, yaitu tentang "membuka kembali", atau memulihkan, buffer yang terbunuh. Itu karena itu hampir tidak mungkin, secara umum - yang terbaik yang bisa dilakukan adalah membuatnya kembali. Tetapi jika yang Anda maksud hanya buffer kunjungan file maka jawabannya mudah, dan jawaban yang diberikan di sini sesuai. Jika demikian, harap edit pertanyaan Anda untuk mencerminkan batasan ini.
Drew
2
Pendekatan alternatif adalah tidak membunuh buffer tersebut. bury-buffer itu bagus. Anda juga bisa membayangkan pendekatan yang lebih bagus, misalnya kill-buffer-later (yang belum ditentukan) yang akan mengubur-buffer segera dan mengatur timer untuk membunuh buffer setelah beberapa menit. Atau kill-buffer-mungkin-nanti yang akan membunuh buffer jika mengunjungi file, dan menunda kematiannya jika tidak (mungkin juga menambahkan spasi ke namanya untuk menghindari kekacauan saat menggunakan Cx b).
YoungFrog
@YoungFrog, Persis, saya sudah membahas peluang ini dalam jawaban saya.
Mark Karpov

Jawaban:

27

Inilah alternatif sederhana lain yang tidak diperlukan recentf. Mengaitkan fungsi pertama ke dalam kill-buffer-hookakan mendorong nama file yang terkait dengan buffer ke daftar. (Perhatikan bahwa, jika Anda membunuh buffer yang tidak mengunjungi file, itu akan hilang selamanya.) Fungsi yang terakhir mengeluarkan file itu dari daftar dan mengunjunginya:

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

Perhatikan itu killed-file-listadalah daftar, jadi Anda bisa, misalnya, menulis fungsi yang lebih rumit untuk menelusuri daftar itu, daripada yang sederhana yang dijelaskan di sini: terserah Anda seberapa banyak yang ingin Anda lakukan dengannya.

EDIT: maaf, saya melewatkan ketentuan terakhir di Q Anda tentang menginginkan daftar file yang dapat dipilih. Fungsi berikut sedikit lebih bagus daripada versi di atas sejauh yang digunakan completing-readuntuk membiarkan Anda menentukan file yang Anda inginkan. Jika Anda menggunakan sesuatu seperti ido, itu akan memungkinkan Anda menggilir semua file yang telah Anda bunuh di sesi saat ini, default ke yang terbaru. Perhatikan bahwa ini mengandaikan bahwa Anda telah diminta 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
sumber
5

Saya ingin bertanya: "Apakah Anda benar-benar ingin membunuhnya?" Memang, membunuh penyangga adalah hal yang biasa di dunia Emacs, tetapi begitu terbunuh, penyangga hilang, dan seperti yang ditunjukkan pertanyaan Anda, itu tidak selalu diinginkan.

Namun kita dapat memilih cara lain, sehingga Anda tidak perlu mengembalikan buffer yang mati - hanya lebih memilih mengubur daripada membunuh. Lihatlah paket Kill atau Bury Alive , tersedia melalui MELPA .

Dari deskripsi paket:

Pernahkah Anda membunuh penyangga yang mungkin ingin Anda hidupi? Motivasi untuk membunuh biasanya "keluar dari jalan saya untuk saat ini", dan membunuh mungkin bukan pilihan terbaik dalam banyak kasus kecuali RAM Anda sangat-sangat terbatas. Paket ini memungkinkan untuk mengajar Emacs buffer yang ingin kita bunuh dan yang mana yang kita pilih untuk dikubur hidup-hidup.

Ketika kita benar-benar ingin membunuh buffer, ternyata tidak semua buffer ingin mati dengan cara yang sama. Paket ini memungkinkan untuk menentukan cara membunuh berbagai jenis buffer. Ini mungkin sangat berguna ketika Anda bekerja dengan beberapa buffer yang memiliki proses terkait, misalnya.

Tetapi kadang-kadang Anda mungkin ingin menyingkirkan sebagian besar penyangga dan membawa Emacs ke kondisi yang kurang lebih perawan. Anda mungkin tidak ingin membunuh buffer awal dan mungkin juga buffer terkait ERC. Anda dapat menentukan buffer yang harus dibersihkan.

Mark Karpov
sumber
4

Saya menggunakan solusi ini dari posting SO ini dan berfungsi dengan baik.

Solusinya elegan tetapi tidak sempurna; itu menyimpan daftar buffer aktif dan mengembalikan file pertama dari daftar -f terbaru yang bukan milik daftar buffer aktif.

;; Buka kembali buffer yang terakhir terbunuh
;; Sumber: https://stackoverflow.com/questions/10394213/emacs-reopen-previous-killed-buffer
(membutuhkan 'cl)
(memerlukan 'Recentf)
(mode terkini 1)
(defun undo-kill-buffer ()
  (interaktif)
  (let ((file aktif) (loop for buf in (buffer-list))
                            kapan (buffer-file-name buf) kumpulkan itu)))
    (loop untuk file di daftarf terbaru)
          kecuali (file anggota file aktif) kembali (file file menemukan))))
Kaushal Modi
sumber
3

Anda harus menghidupkan recentf-mode. Untuk melakukannya, jalankan M-x recentf-mode. Kemudian, fungsi mungkin tidak berfungsi sampai Anda membuka atau membunuh beberapa buffer baru; Saya pikir Anda tidak akan recentf-listmengisinya.

Jika Anda ingin ini diaktifkan ketika Emacs mulai, taruh ini di file init Anda:

(recentf-mode)

Anda kemudian dapat meletakkan yang defunAnda temukan di sana, dan mengikatnya ke kunci, jika Anda mau.

Satu kelemahan dari mode ini tampaknya adalah bahwa mode latestf dibangun untuk melacak openedfile, bukan yang terbunuh. Jadi, jika Anda menjalankan fungsi dua kali, itu tidak akan membuka kembali file kedua Anda yang paling baru-baru ini terbunuh.

kawan
sumber
4
Meskipun Emacs 24 secara efektif membuat opsi ini untuk mode minor, saya masih cenderung untuk menulis (recentf-mode 1)dengan argumen eksplisit, sehingga seseorang mengevaluasi kembali file init mereka di bawah Emacs 23 tidak berakhir mematikan mode lagi.
phils
1

ErgoEmacs memiliki fungsi close-current-bufferyang secara khusus menyimpan daftar buffer yang baru saja ditutup:

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

Jadi menggunakan ini dapat membuka kembali sesi tertutup dengan buffer ini

;; 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
sumber
1

EDIT: Saya tidak memperhatikan ketika menjawab, dan menjawab sesuatu yang OP tidak tanyakan. Sekali lagi, saya minta maaf. Terima kasih atas kata-kata Anda, @CodyChan.

Yah, saya bukan veteran Emacs, dan mungkin ini mungkin telah tersedia hanya pada versi terbaru. Saya tahu saya akan datang beberapa tahun kemudian, tapi mungkin itu bisa membantu orang lain, karena pencarian saya membuat saya di sini.

Saya menggunakan Emacs v25.2.1, recentfsudah tersedia di sini dan memiliki fungsi siap yang melakukan apa yang Anda butuhkan. Saya sudah mengaktifkannya di versi sebelumnya, jadi saya .emacspunya:

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

Dan ini bekerja dengan baik untuk saya. Tentu saja, ubah pintasan untuk apa pun yang Anda sukai.

Charles Roberto Canato
sumber
2
Tampaknya fungsinya sudah ada sejak lama, yaitu 2005 menurut file ChangeLog di pohon kode sumber Emacs. Itu berfungsi, dan bahkan dapat bekerja untuk membuka kembali buffer tertutup dari sesi Emacs sebelumnya, tetapi tampaknya ia tidak dapat membuat daftar buffer yang ditutup untuk membiarkan saya memilih satu dari daftar.
CodyChan
2
Jadi tidak dibuka kembali hanya membunuh buffer khusus tetapi membuka kembali file yang baru dibuka.
CodyChan
@CodyChan, saya sangat menyesal dan tentu saja Anda benar. Itu akan menjadi file yang lebih baru dibuka dan bukan yang Anda minta. Saya akan segera menghapus jawabannya, saya minta maaf kepada Anda dan teman-teman lain.
Charles Roberto Canato
3
Tidak perlu menghapus jawaban ini, mungkin seseorang hanya ingin solusi Anda membuka kembali file yang baru dibuka. :)
CodyChan