Jak ponownie otworzyć właśnie zabity bufor, taki jak CSt w przeglądarce Firefox?

35

Czasami przypadkowo zabijam bufor i chcę go ponownie otworzyć, tak jak CSt, aby cofnąć zamkniętą kartę w Firefoksie, ale nie ma wbudowanego polecenia w Emacsie, defun undo-kill-bufferw 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)))))

w ogóle nie działa. Jeśli znasz elisp, jak rozwiązać ten problem?

Jeśli może wyświetlić listę zamkniętych buforów i je, mogę wybrać jeden z nich do ponownego otwarcia, byłoby lepiej.

CodyChan
źródło
7
Żadna z podanych dotąd odpowiedzi nie odpowiada na postawione pytanie, które dotyczy „ponownego otwarcia” lub przywrócenia zabitego bufora. Jest tak, ponieważ ogólnie rzecz biorąc jest to prawie niemożliwe - najlepszym, co można by zrobić, byłoby odtworzenie go. Ale jeśli masz na myśli tylko bufory do przeglądania plików, odpowiedź jest łatwa, a podane tutaj odpowiedzi są odpowiednie. W takim przypadku edytuj pytanie, aby odzwierciedlić to ograniczenie.
Drew
2
Alternatywnym podejściem jest nie zabijanie tych buforów. Bury-bufor jest fajny. Można również wyobrazić sobie bardziej wyrafinowane podejście, np. (Jeszcze do zdefiniowania) kill-buffer-later, który natychmiast zakopuje bufor i ustawia timer, aby zabić bufor po kilku minutach. Lub też kill-buffer-może-później, który zabiłby bufor, jeśli odwiedzi plik, i opóźni jego śmierć, jeśli nie jest (może także wstawić spację do swojej nazwy, aby uniknąć bałaganu podczas korzystania z Cx b).
YoungFrog,
@YoungFrog, Dokładnie wykorzystałem tę okazję w mojej odpowiedzi.
Mark Karpov

Odpowiedzi:

27

Oto kolejna prosta alternatywa, która nie wymaga recentf. Podłączenie pierwszej funkcji kill-buffer-hookspowoduje wypchnięcie nazwy pliku związanej z buforem na listę. (Pamiętaj, że jeśli zabijesz bufor, który nie odwiedza pliku, zniknie na dobre.) Ta ostatnia funkcja usuwa ten plik z listy i odwiedza go:

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

Zauważ, że killed-file-listjest to lista, więc możesz na przykład napisać bardziej skomplikowaną funkcję, aby cyklicznie przewijać tę listę, niż prostą opisaną tutaj: to od ciebie zależy, ile chcesz z nią zrobić.

EDYCJA: przepraszam, brakowało mi ostatniego przepisu w twoim Q na temat listy plików do wyboru. Poniższa funkcja jest nieco bardziej wyszukana niż powyższa wersja, ponieważ completing-readumożliwia określenie, który z zabitych plików chcesz. Jeśli używasz czegoś podobnego ido, pozwoli Ci to na przeglądanie wszystkich plików, które zabiłeś w bieżącej sesji, domyślnie do najnowszej. Pamiętaj, że zakłada, że ​​już wymagałeś 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
źródło
5

Chciałbym cię zapytać: „Czy naprawdę chcesz to zabić?”. Rzeczywiście zabijanie bufora jest tak powszechną rzeczą w świecie Emacsa, ale po zabiciu bufor zniknął, a jak pokazuje twoje pytanie, nie zawsze jest to pożądane.

Możemy jednak wybrać inny sposób, abyś nigdy nie musiał przywracać zabitego bufora - po prostu wolisz grzebać niż zabijać. Spójrz na pakiet Kill or Bury Alive , jest on dostępny za pośrednictwem MELPA .

Z opisu paczki:

Czy zabiłeś kiedyś bufor, który możesz zostawić przy życiu? Motywacja do zabijania jest zazwyczaj „zejdź mi z drogi”, a zabijanie może nie być najlepszym wyborem w wielu przypadkach, chyba że twoja pamięć RAM jest bardzo, bardzo, bardzo ograniczona. Ten pakiet pozwala nauczyć Emacsa, które bufory chcemy zabić, a które wolimy pochować żywcem.

Kiedy naprawdę chcemy zabić bufor, okazuje się, że nie wszystkie bufory chcieliby umrzeć w ten sam sposób. Pakiet pozwala określić, jak zabijać różnego rodzaju bufory. Może to być szczególnie przydatne, na przykład podczas pracy z jakimś buforem, który ma powiązany proces.

Ale czasami możesz chcieć pozbyć się większości buforów i doprowadzić Emacsa do mniej więcej dziewiczego stanu. Prawdopodobnie nie chcesz zabijać bufora scratch i być może także buforów związanych z ERC. Możesz określić, które bufory mają zostać usunięte.

Mark Karpov
źródło
4

Korzystam z tego rozwiązania z tego postu SO i działa dobrze.

Rozwiązanie jest eleganckie, ale nie idealne; przechowuje listę aktywnych buforów i zwraca pierwszy plik z ostatniej listy, który nie należy do listy aktywnych buforów.

;; Ponownie otwórz ostatni zabity bufor
;; Źródło: https://stackoverflow.com/questions/10394213/emacs-reopen-previous-killed-buffer
(wymaga „cl)
(wymaga „niedawnego”)
(najnowszy tryb 1)
(defun undo-kill-buffer ()
  (interaktywny)
  (let ((active-files (loop for buf in (lista buforów)
                            kiedy (nazwa bufora-nazwa-buf)))))
    (pętla dla pliku na liście najnowszych
          chyba, że ​​(plik członkowski plików aktywnych) zwraca (plik pliku znajdowania))))
Kaushal Modi
źródło
3

Musisz włączyć recentf-mode. Aby to zrobić, biegnij M-x recentf-mode. Następnie funkcja może nie działać, dopóki nie otworzysz lub zabijesz niektórych nowych buforów; Nie sądzę, że się recentf-listwypełniłeś.

Jeśli chcesz, aby ta funkcja była włączona podczas uruchamiania Emacsa, umieść to w pliku init:

(recentf-mode)

Następnie możesz umieścić tam defunznalezione i powiązać je z kluczem, jeśli chcesz.

Jednym minusem tego trybu wydaje się być to, że tryb niedawny jest zbudowany do śledzenia openedplików, a nie zabitych. Tak więc, jeśli uruchomisz tę funkcję dwukrotnie, nie otworzy ona ponownie twojego ostatniego zabitego pliku.

zck
źródło
4
Chociaż Emacs 24 efektywnie uczynił to opcjonalnym dla mniejszych trybów, nadal będę skłonny pisać (recentf-mode 1)z wyraźnym argumentem, aby ktoś ponownie oceniający swój plik init pod Emacs 23 nie skończył ponownie wyłączać tego trybu.
phils
1

ErgoEmacs ma funkcję, close-current-bufferktóra w szczególności prowadzi listę ostatnio zamkniętych buforów:

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

Korzystając z nich, można ponownie otworzyć tę sesję za pomocą bufora zamkniętego

;; 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)))
Cegła suszona na słońcu
źródło
1

EDYCJA: Nie zwracałem uwagi podczas odpowiadania i odpowiedziałem na coś innego, o co OP nie zapytał. Jeszcze raz przepraszam. Dziękuję za słowa, @CodyChan.

Cóż, nie jestem weteranem Emacsa i być może stało się to możliwe tylko w najnowszych wersjach. Wiem, że przyjadę kilka lat później, ale może to może być pomocne dla innych, ponieważ moje poszukiwania mnie tu doprowadziły.

Korzystam z Emacsa v.2.2.1, recentfjest już dostępny tutaj i ma gotową funkcję, która robi to, czego potrzebujesz. Aktywowałem go już w przeszłości na starszych wersjach, więc .emacsmam:

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

I to działało idealnie dla mnie. Oczywiście zmień skrót na to, co bardziej ci się podoba.

Charles Roberto Canato
źródło
2
Wygląda na to, że funkcja istniała już dawno temu, czyli w 2005 r., Zgodnie z plikiem ChangeLog w drzewie kodu źródłowego Emacsa. Działa, a nawet może ponownie otworzyć zamknięty bufor z poprzedniej sesji Emacsa, ale wygląda na to, że nie może wyświetlić zamkniętych buforów, aby pozwolić mi wybrać jeden z listy.
CodyChan,
2
Więc nie otwiera się ponownie specjalnie zabity bufor, ale ponownie otwiera ostatnio otwarte pliki.
CodyChan,
@CodyChan, bardzo mi przykro i oczywiście masz rację. To byłby ostatnio otwarty plik, a nie to, o co prosiłeś. Wkrótce usunę odpowiedź, przepraszam ciebie i innych partnerów.
Charles Roberto Canato,
3
Aby niepotrzebnie usunąć tę odpowiedź, być może ktoś po prostu chce, aby twoje rozwiązanie po prostu ponownie otwierało ostatnio otwierane pliki. :)
CodyChan