Как открыть только что уничтоженный буфер, как 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, как решить эту проблему?

Если он может показать список закрытых буферов и их, я могу выбрать один из них, чтобы открыть, что было бы лучше.

CodyChan
источник
7
Ни один из приведенных ответов не отвечает на поставленный вопрос, который касается «повторного открытия» или восстановления уничтоженного буфера. Это потому, что в общем-то это практически невозможно - лучшее, что можно сделать, - это воссоздать его. Но если вы имеете в виду только буферы для доступа к файлам, тогда ответ прост, и ответы, приведенные здесь, уместны. Если это так, то отредактируйте ваш вопрос, чтобы отразить это ограничение.
Дрю
2
Альтернативный подход - не уничтожать эти буферы. хоронить хорошо. Вы могли бы также представить более причудливый подход, например (еще предстоит определить) kill-buffer-позже, который бы сразу же закапывал буфер и устанавливал таймер для уничтожения буфера через несколько минут. Или kill-buffer-возможно-позже, который убил бы буфер, если он посещает файл, и задержал бы его смерть, если это не так (возможно, также добавьте пробел к его имени, чтобы избежать беспорядка при использовании 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это список, поэтому вы можете, например, написать более сложную функцию для циклического перемещения по этому списку, а не простую, описанную здесь: вам решать, сколько вы хотите с ним сделать.

РЕДАКТИРОВАТЬ: извините, я пропустил последнее положение в вашей Q о желании список файлов, из которых можно выбирать. Следующая функция немного сложнее, чем версия выше, поскольку она 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 или Bury Alive , он доступен через MELPA .

Из описания пакета:

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

Когда мы действительно хотим уничтожить буфер, оказывается, что не все буферы хотели бы умереть одинаково. Пакет позволяет указать, как убивать различные виды буферов. Это может быть особенно полезно, например, когда вы работаете с некоторым буфером, с которым связан процесс.

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

Марк Карпов
источник
4

Я использую это решение из этого поста, и он отлично работает.

Решение элегантное, но не идеальное; он хранит список активных буферов и возвращает первый файл из списка latestf, который не принадлежит списку активных буферов.

;; Откройте последний убитый буфер
;; Источник: https://stackoverflow.com/questions/10394213/emacs-reopen-previous-killed-buffer
(требуется 'кл)
(требуется 'недавно)
(недавний режим 1)
(defun undo-kill-buffer ()
  (Интерактивный)
  (let ((active-files (цикл для буфера в (буфер-список))
                            когда (буфер-файл-имя-буф) собери его)))
    (цикл для файла в RecentF-список
          exc (файл-файл активных файлов) return (файл-файл поиска))))
Каушал Моди
источник
3

Вам нужно включить recentf-mode. Для этого беги M-x recentf-mode. Тогда функция может не работать, пока вы не откроете или не уничтожите несколько новых буферов; Я не думаю, что вы recentf-listзаполнили.

Если вы хотите, чтобы это было включено при запуске Emacs, поместите это в ваш файл инициализации:

(recentf-mode)

Затем вы можете положить defunнайденный там и привязать его к ключу, если хотите.

Недостатком этого режима является то, что недавно созданный режим предназначен для отслеживания openedфайлов, а не уничтоженных. Таким образом, если вы запустите эту функцию дважды, она не откроет ваш второй из недавно уничтоженных файлов.

zck
источник
4
Хотя Emacs 24 фактически сделал это необязательным для второстепенных режимов, я все же был бы склонен писать (recentf-mode 1)с явным аргументом, так что кто-то, переоценивающий свой файл инициализации в 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

РЕДАКТИРОВАТЬ: Я не обращал внимания при ответе, и ответил что-то еще, что ОП не спросил. Еще раз прошу прощения. Спасибо за ваши слова, @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