Emacs: Open Last Closed File 🚀

By Xah Lee. Date: . Last updated: .

This page shows a command to open last closed file.

put this in your Emacs Init File:

(defcustom xah-recently-closed-buffers-max 40 "The maximum length for `xah-recently-closed-buffers'."
  :type 'integer)

(defvar xah-recently-closed-buffers nil "A Alist of recently closed buffers.
Each element is (bufferName . filePath).
The max number to track is controlled by the variable `xah-recently-closed-buffers-max'.")

(defun xah-add-to-recently-closed (&optional BufferName BufferFileName)
  "Add to `xah-recently-closed-buffers'.
Version: 2023-03-02"
  (let ((xbn (if BufferName BufferName (buffer-name)))
        (xbfn (if BufferFileName BufferFileName buffer-file-name)))
    (setq xah-recently-closed-buffers (cons (cons xbn xbfn) xah-recently-closed-buffers)))
  (when (> (length xah-recently-closed-buffers) xah-recently-closed-buffers-max)
    (setq xah-recently-closed-buffers (butlast xah-recently-closed-buffers 1))))

(defvar xah-temp-dir-path nil "Path to temp dir used by xah commands.
by default, the value is dir temp at `user-emacs-directory'.
Version: 2023-03-21")

(setq xah-temp-dir-path
      (if xah-temp-dir-path
        (concat user-emacs-directory "temp/")))

(defun xah-close-current-buffer ()
  "Close the current buffer with possible backup of modified file.

• If the buffer a file and not modified, kill it.
• If the buffer a file and modified, do nothing. Print a message.
• If the buffer is not a file, first save it to `xah-temp-dir-path' named untitled_‹datetime›_‹randomhex›.txt.

If the buffer is a file, add the path to the list `xah-recently-closed-buffers'.

URL `http://xahlee.info/emacs/emacs/elisp_close_buffer_open_last_closed.html'
Version: 2016-06-19 2023-09-13 2023-09-27"
   ;; ((eq major-mode 'minibuffer-inactive-mode) (minibuffer-keyboard-quit))
   ;; ((active-minibuffer-window) (minibuffer-keyboard-quit))
   ((minibufferp (current-buffer)) (minibuffer-keyboard-quit))
   ((and buffer-file-name (not (buffer-modified-p)))
    (xah-add-to-recently-closed (buffer-name) buffer-file-name)
   ((and buffer-file-name (buffer-modified-p))
    (message "buffer file modified. Save it first.\n%s" buffer-file-name)
    ;; (let ((xnewName
    ;;            (format "%s~%s~"
    ;;                    buffer-file-name
    ;;                    (format-time-string "%Y-%m-%d_%H%M%S"))))
    ;;       (write-region (point-min) (point-max) xnewName)
    ;;       (print (format "The modified version is saved at
    ;; %s
    ;; call xah-open-last-closed twice to open." xnewName))
    ;;       (xah-add-to-recently-closed (buffer-name) xnewName)
    ;;       (xah-add-to-recently-closed (buffer-name) buffer-file-name)
    ;;       (kill-buffer))
   ((and (not buffer-file-name) (xah-user-buffer-p) (not (eq (point-max) 1)))
    (let ((xnewName (format "%suntitled_%s_%x.txt"
                            (format-time-string "%Y%m%d_%H%M%S")
                            (random #xfffff))))
      (write-region (point-min) (point-max) xnewName)
      (xah-add-to-recently-closed (buffer-name) xnewName)
   (t (kill-buffer))))

(defun xah-open-last-closed ()
  "Open the last closed file.
URL `http://xahlee.info/emacs/emacs/elisp_close_buffer_open_last_closed.html'
Version: 2016-06-19 2022-03-22"
  (if (> (length xah-recently-closed-buffers) 0)
      (find-file (cdr (pop xah-recently-closed-buffers)))
    (progn (message "No recently close buffer in this session."))))

(defun xah-open-recently-closed ()
  "Open recently closed file.
Prompt for a choice.

URL `http://xahlee.info/emacs/emacs/elisp_close_buffer_open_last_closed.html'
Version: 2016-06-19 2023-08-25 2023-09-19"
   (let ((completion-ignore-case t))
      (mapcar (lambda (f) (cdr f)) xah-recently-closed-buffers)
      nil t

(defun xah-list-recently-closed ()
  "List recently closed file.

URL `http://xahlee.info/emacs/emacs/elisp_close_buffer_open_last_closed.html'
Version: 2016-06-19"
  (let ((xbuf (generate-new-buffer "*recently closed*")))
    (switch-to-buffer xbuf)
    (mapc (lambda (xf) (insert (cdr xf) "\n"))

Give these commands keys:

(global-set-key (kbd "C-x k") 'xah-close-current-buffer)
(global-set-key (kbd "C-S-t") 'xah-open-last-closed) ; control+shift+t

[see Emacs Keys: Define Key]