Як знову відкрити щойно вбитий буфер, як CSt у браузері Firefox?


35

Іноді я випадково вбиваю буфер і хочу його знову відкрити, як CSt, щоб скасувати закриту вкладку у Firefox, але в Emacs немає вбудованої команди, defun undo-kill-bufferв 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)))))

зовсім не працює. Якщо ви знаєте Elisp, як вирішити цю проблему?

Якщо він може показати список закритих буферів, і я можу вибрати один із них для повторного відкриття, це було б краще.


7
Жодна з наведених відповідей поки що не відповідає на поставлене запитання, яке стосується "повторного відкриття" або відновлення вбитого буфера. Це тому, що це майже неможливо, загалом - найкраще, що можна було б зробити, це відновити його. Але якщо ви маєте на увазі лише буфери для відвідування файлів, то відповідь проста, і наведені тут відповіді є відповідними. Якщо це так, то будь ласка, відредагуйте своє запитання, щоб відобразити це обмеження.
Дрю

2
Альтернативний підхід - не вбивати ці буфери. поховати-буфер приємно. Ви також можете уявити більш фантастичний підхід, наприклад, (ще ​​не визначено) kill-buffer-later, який би негайно поховав буфер і встановив таймер, щоб знищити буфер через кілька хвилин. Або вбивчий буфер-можливо-пізніше, який би вбивство буфера, якщо він відвідує файл, і затримує його загибель, якщо його немає (можливо, також додайте пробіл до його імені, щоб уникнути неполадок при використанні Cx b).
YoungFrog

@YoungFrog, Точно, я вирішив цю можливість у своїй відповіді.
Марк Карпов

Відповіді:


27

Ось ще одна проста альтернатива, яка не вимагає recentf. Якщо підключити першу функцію kill-buffer-hook, ім'я файлу, пов’язане з буфером, висуне на список. (Зверніть увагу, що якщо ви вб'єте буфер, який не відвідує файл, це піде назавжди.) Остання функція вискакує, що видаляє зі списку та відвідує його:

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

Зауважте, що killed-file-listце список, тому ви могли, наприклад, написати більш складну функцію для переходу через цей список, а не просту, описану тут: від вас залежить, скільки ви хочете зробити з ним.

EDIT: вибачте, я пропустив останнє положення у вашому запитанні про те, що я хочу вибрати список файлів, з яких можна вибрати. Наступна функція трохи фантазіїше, ніж версія вище, наскільки вона використовується, completing-readщоб ви могли вказати, який із вбитих файлів ви хочете. Якщо ви використовуєте щось на кшталт ido, це дозволить вам переглядати всі файли, які ви убили в поточному сеансі, за замовчуванням до останнього. Зауважте, що це передбачає, що ви вже вимагали 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

Я хотів би запитати вас: "Ви справді хочете його вбити?". Дійсно, вбивство буфера - це така поширена річ у світі Emacs, але колись убитий, буфера вже немає, і як показує ваше запитання, це не завжди бажано.

Однак ми можемо вибрати інший спосіб, так що вам ніколи не потрібно буде відновлювати вбитий буфер - просто віддайте перевагу закопуванню, ніж вбивству. Погляньте на пакет Kill or Bury Alive , доступний через MELPA .

З опису пакета:

Ви коли-небудь вбивали якийсь буфер, який, можливо, хочете залишити живим? Мотивація на вбивство, як правило, "вийти з мого шляху поки що", і вбивство може бути не найкращим вибором у багатьох випадках, якщо ваша ОЗУ дуже-дуже обмежена. Цей пакет дозволяє навчити Emacs, які буфери ми хочемо вбити, а які ми вважаємо за краще поховати живими.

Коли ми справді хочемо вбити буфер, виявляється, що не всі буфери хотіли б гинути однаково. Пакет дозволяє вказати як знищувати різні види буферів. Це може бути особливо корисно, наприклад, коли ви працюєте з деяким буфером, з яким пов'язаний процес.

Але іноді ви можете позбутися більшості буферів і привести Emacs до якогось більш-менш незайманого стану. Ви, мабуть, не хочете вбивати буфер нуля, а може бути і буфери, пов'язані з ERC. Ви можете вказати, які буфери продувати.


4

Я використовую це рішення з цієї публікації SO і воно прекрасно працює.

Рішення елегантне, але не ідеальне; він зберігає список активних буферів і повертає перший файл зі списку recentf, який не належить до списку активних буферів.

;; Повторно відкрийте останній вбитий буфер
;; Джерело: https://stackoverflow.com/questions/10394213/emacs-reopen-previous-killed-buffer
(потрібно 'cl)
(потрібно "recentf)
(нещодавній режим 1)
(вимкнути буфер скасування вбивства ()
  (інтерактивний)
  (нехай ((active-файли (цикл для buf в (буфер-список))
                            коли (buffer-file-name buf) збирає його)))
    (цикл для файлу в recentf-списку
          якщо (файли-учасники активні файли) не повертаються (файл пошуку-файл))))

3

Вам потрібно включити recentf-mode. Для цього запустіть M-x recentf-mode. Потім функція може не працювати, поки ви не відкриєте або не вб'єте деякі нові буфери; Я не думаю, що ви його recentf-listзаповнили.

Якщо ви хочете, щоб це було ввімкнено під час запуску Emacs, покладіть це у свій файл init:

(recentf-mode)

Потім ви можете помістити defunзнайдене туди і прив’язати його до ключа, якщо хочете.

Одним із недоліків цього режиму є те, що режим nedaf побудований для відстеження openedфайлів, а не вбитих. Отже, якщо ви запускаєте функцію двічі, вона не відкриє ваш другий за останній час вбитий файл.


4
Хоча Emacs 24 фактично зробив це необов’язковим для другорядних режимів, я все одно схильний писати (recentf-mode 1)з явним аргументом, щоб хтось повторно оцінював свій файл init у Emacs 23, не закінчуючи знову вимикати режим.
філс

1

ErgoEmacs має функцію, close-current-bufferяка зокрема зберігає список нещодавно закритих буферів:

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

Таким чином, використовуючи цей, можна повторно відкрити цей сеанс закритого буфера за допомогою

;; 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: Я не звертав уваги, коли відповідав, і відповів на щось інше, що ОП не запитувало. Ще раз пробачте. Дякую за ваші слова, @CodyChan.

Ну, я не ветеран Emacs, і, можливо, це стало доступним лише в останніх версіях. Я знаю, що я приїжджаю через кілька років, але, можливо, це може бути корисним для інших, оскільки мій пошук привів мене сюди.

Я на Emacs v25.2.1, recentfвже доступний тут і має готову функцію, яка робить все, що вам потрібно. Я вже активував це раніше в старих версіях, тому у мене .emacsє:

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

І це прекрасно працювало для мене. Звичайно, змініть ярлик на те, що вам більше подобається.


2
Здається, функція вже існувала давно, а це 2005 рік за файлом ChangeLog у дереві вихідного коду Emacs. Це спрацьовує, і він може навіть працювати над повторним відкриттям закритого буфера з попереднього сеансу Emacs, але, здається, він не може перелічити закриті буфери, щоб дозволити мені вибрати один зі списку.
CodyChan

2
Таким чином він не відкриває спеціально щойно вбитий буфер, але заново відкриває нещодавно відкриті файли.
CodyChan

@CodyChan, мені дуже шкода і, звичайно, ти маєш рацію. Це був би нещодавно відкритий файл, а не те, що ви запитували. Я скоро видалю відповідь, вибачаюся перед вами та іншими товаришами.
Чарльз Роберто Канато

3
Необхідно видаляти цю відповідь, можливо, хтось просто хоче, щоб ваше рішення просто заново відкрило нещодавно відкриті файли. :)
CodyChan
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.